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/editbrowsebox.hxx>
22 #include <tools/debug.hxx>
23 #include <vcl/image.hxx>
24 #include <vcl/settings.hxx>
25 #include <vcl/window.hxx>
26 #include <vcl/svapp.hxx>
28 #include <bitmaps.hlst>
31 #include "editbrowseboximpl.hxx"
32 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
41 GetFocusFlags
getRealGetFocusFlags( vcl::Window
* _pWindow
)
43 GetFocusFlags nFlags
= GetFocusFlags::NONE
;
44 while ( _pWindow
&& nFlags
== GetFocusFlags::NONE
)
46 nFlags
= _pWindow
->GetGetFocusFlags( );
47 _pWindow
= _pWindow
->GetParent();
53 using namespace ::com::sun::star::uno
;
54 using namespace com::sun::star::accessibility::AccessibleEventId
;
57 IEditImplementation::~IEditImplementation()
63 void EditBrowserHeader::DoubleClick()
65 sal_uInt16 nColId
= GetCurItemId();
68 sal_uInt32 nAutoWidth
= static_cast<EditBrowseBox
*>(GetParent())->GetAutoColumnWidth(nColId
);
69 if (nAutoWidth
!= static_cast<EditBrowseBox
*>(GetParent())->GetColumnWidth(nColId
))
71 static_cast<EditBrowseBox
*>(GetParent())->SetColumnWidth(nColId
, nAutoWidth
);
72 static_cast<EditBrowseBox
*>(GetParent())->ColumnResized(nColId
);
79 void EditBrowseBox::BrowserMouseEventPtr::Clear()
84 void EditBrowseBox::BrowserMouseEventPtr::Set(const BrowserMouseEvent
* pEvt
, bool bIsDown
)
86 if (pEvt
== pEvent
.get())
94 pEvent
.reset(new BrowserMouseEvent(pEvt
->GetWindow(),
104 EditBrowseBox::EditBrowseBox( vcl::Window
* pParent
, EditBrowseBoxFlags nBrowserFlags
, WinBits nBits
, BrowserMode _nMode
)
105 :BrowseBox( pParent
, nBits
, _nMode
)
106 ,nStartEvent(nullptr)
108 ,nCellModifiedEvent(nullptr)
109 ,m_pFocusWhileRequest(nullptr)
115 ,bActiveBeforeTracking( false )
116 ,m_nBrowserFlags(nBrowserFlags
)
119 m_aImpl
.reset(new EditBrowseBoxImpl
);
121 SetCompoundControl(true);
123 ImplInitSettings(true, true, true);
125 pCheckBoxPaint
= VclPtr
<CheckBoxControl
>::Create(&GetDataWindow());
126 pCheckBoxPaint
->SetPaintTransparent( true );
127 pCheckBoxPaint
->SetBackground();
130 void EditBrowseBox::Init()
135 EditBrowseBox::~EditBrowseBox()
140 void EditBrowseBox::dispose()
143 Application::RemoveUserEvent(nStartEvent
);
145 Application::RemoveUserEvent(nEndEvent
);
146 if (nCellModifiedEvent
)
147 Application::RemoveUserEvent(nCellModifiedEvent
);
149 pCheckBoxPaint
.disposeAndClear();
150 m_pFocusWhileRequest
.clear();
152 BrowseBox::dispose();
156 void EditBrowseBox::RemoveRows()
159 nEditRow
= nPaintRow
= -1;
163 VclPtr
<BrowserHeader
> EditBrowseBox::CreateHeaderBar(BrowseBox
* pParent
)
165 pHeader
= imp_CreateHeaderBar(pParent
);
167 pHeader
->SetUpdateMode(false);
171 VclPtr
<BrowserHeader
> EditBrowseBox::imp_CreateHeaderBar(BrowseBox
* pParent
)
173 return VclPtr
<EditBrowserHeader
>::Create(pParent
);
176 void EditBrowseBox::LoseFocus()
178 BrowseBox::LoseFocus();
182 void EditBrowseBox::GetFocus()
184 BrowseBox::GetFocus();
186 // This should handle the case that the BrowseBox (or one of its children)
187 // gets the focus from outside by pressing Tab
188 if (IsEditing() && Controller()->GetWindow().IsVisible())
189 Controller()->GetWindow().GrabFocus();
191 DetermineFocus(getRealGetFocusFlags(this));
194 bool EditBrowseBox::SeekRow(sal_Int32 nRow
)
200 IMPL_LINK_NOARG(EditBrowseBox
, StartEditHdl
, void*, void)
202 nStartEvent
= nullptr;
206 if (!ControlHasFocus() && (m_pFocusWhileRequest
.get() == Application::GetFocusWindow()))
207 aController
->GetWindow().GrabFocus();
211 void EditBrowseBox::PaintField( vcl::RenderContext
& rDev
, const tools::Rectangle
& rRect
,
212 sal_uInt16 nColumnId
) const
214 if (nColumnId
== HandleColumnId
)
217 PaintStatusCell(rDev
, rRect
);
221 // don't paint the current cell
222 if (rDev
.GetOwnerWindow() == &GetDataWindow())
223 // but only if we're painting onto our data win (which is the usual painting)
224 if (nPaintRow
== nEditRow
)
226 if (IsEditing() && nEditCol
== nColumnId
&& aController
->GetWindow().IsVisible())
229 PaintCell(rDev
, rRect
, nColumnId
);
233 Image
EditBrowseBox::GetImage(RowStatus eStatus
) const
236 bool bNeedMirror
= IsRTLEnabled();
240 aBitmap
= BitmapEx(BMP_CURRENT
);
243 aBitmap
= BitmapEx(BMP_CURRENTNEW
);
246 aBitmap
= BitmapEx(BMP_MODIFIED
);
247 bNeedMirror
= false; // the pen is not mirrored
250 aBitmap
= BitmapEx(BMP_NEW
);
253 aBitmap
= BitmapEx(BMP_DELETED
);
256 aBitmap
= BitmapEx(BMP_PRIMARYKEY
);
258 case CURRENT_PRIMARYKEY
:
259 aBitmap
= BitmapEx(BMP_CURRENT_PRIMARYKEY
);
262 aBitmap
= BitmapEx(BMP_FILTER
);
265 aBitmap
= BitmapEx(BMP_HEADERFOOTER
);
272 aBitmap
.Mirror( BmpMirrorFlags::Horizontal
);
274 return Image(aBitmap
);
277 void EditBrowseBox::PaintStatusCell(OutputDevice
& rDev
, const tools::Rectangle
& rRect
) const
282 RowStatus eStatus
= GetRowStatus( nPaintRow
);
283 EditBrowseBoxFlags nBrowserFlags
= GetBrowserFlags();
285 if (nBrowserFlags
& EditBrowseBoxFlags::NO_HANDLE_COLUMN_CONTENT
)
288 // draw the text of the header column
289 if (nBrowserFlags
& EditBrowseBoxFlags::HANDLE_COLUMN_TEXT
)
291 rDev
.DrawText( rRect
, GetCellText( nPaintRow
, 0 ),
292 DrawTextFlags::Center
| DrawTextFlags::VCenter
| DrawTextFlags::Clip
);
295 else if (eStatus
!= CLEAN
&& rDev
.GetOutDevType() == OUTDEV_WINDOW
)
297 Image
aImage(GetImage(eStatus
));
298 // calc the image position
299 Size
aImageSize(aImage
.GetSizePixel());
300 aImageSize
.setWidth( CalcZoom(aImageSize
.Width()) );
301 aImageSize
.setHeight( CalcZoom(aImageSize
.Height()) );
302 Point
aPos( rRect
.TopLeft() );
304 if ( ( aImageSize
.Width() > rRect
.GetWidth() ) || ( aImageSize
.Height() > rRect
.GetHeight() ) )
305 rDev
.SetClipRegion(vcl::Region(rRect
));
307 if ( aImageSize
.Width() < rRect
.GetWidth() )
308 aPos
.AdjustX(( rRect
.GetWidth() - aImageSize
.Width() ) / 2 );
310 if ( aImageSize
.Height() < rRect
.GetHeight() )
311 aPos
.AdjustY(( rRect
.GetHeight() - aImageSize
.Height() ) / 2 );
314 rDev
.DrawImage( aPos
, aImageSize
, aImage
);
316 rDev
.DrawImage( aPos
, aImage
);
318 if (rDev
.IsClipRegion())
319 rDev
.SetClipRegion();
324 void EditBrowseBox::ImplStartTracking()
326 bActiveBeforeTracking
= IsEditing();
327 if ( bActiveBeforeTracking
)
333 BrowseBox::ImplStartTracking();
337 void EditBrowseBox::ImplEndTracking()
339 if ( bActiveBeforeTracking
)
341 bActiveBeforeTracking
= false;
343 BrowseBox::ImplEndTracking();
347 void EditBrowseBox::RowHeightChanged()
351 tools::Rectangle
aRect( GetCellRect( nEditRow
, nEditCol
, false ) );
352 CellControllerRef
aCellController( Controller() );
353 ResizeController( aCellController
, aRect
);
354 aCellController
->GetWindow().GrabFocus();
357 BrowseBox::RowHeightChanged();
361 EditBrowseBox::RowStatus
EditBrowseBox::GetRowStatus(sal_Int32
) const
367 void EditBrowseBox::KeyInput( const KeyEvent
& rEvt
)
369 sal_uInt16 nCode
= rEvt
.GetKeyCode().GetCode();
370 bool bShift
= rEvt
.GetKeyCode().IsShift();
371 bool bCtrl
= rEvt
.GetKeyCode().IsMod1();
376 if (!bCtrl
&& !bShift
&& IsTabAllowed(true))
378 Dispatch(BROWSER_CURSORRIGHT
);
381 BrowseBox::KeyInput(rEvt
);
384 if (!bCtrl
&& !bShift
)
386 if (IsTabAllowed(true))
387 Dispatch(BROWSER_CURSORRIGHT
);
389 // do NOT call BrowseBox::KeyInput : this would handle the tab, but we already now
390 // that tab isn't allowed here. So give the Control class a chance
391 Control::KeyInput(rEvt
);
394 else if (!bCtrl
&& bShift
)
396 if (IsTabAllowed(false))
397 Dispatch(BROWSER_CURSORLEFT
);
399 // do NOT call BrowseBox::KeyInput : this would handle the tab, but we already now
400 // that tab isn't allowed here. So give the Control class a chance
401 Control::KeyInput(rEvt
);
406 BrowseBox::KeyInput(rEvt
);
410 void EditBrowseBox::ChildFocusIn()
412 DetermineFocus(getRealGetFocusFlags(this));
415 void EditBrowseBox::ChildFocusOut()
420 void EditBrowseBox::MouseButtonDown(const BrowserMouseEvent
& rEvt
)
422 // absorb double clicks
423 if (rEvt
.GetClicks() > 1 && rEvt
.GetRow() >= 0)
426 // we are about to leave the current cell. If there is a "this cell has been modified" notification
427 // pending (asynchronously), this may be deadly -> do it synchronously
428 if ( nCellModifiedEvent
)
430 Application::RemoveUserEvent( nCellModifiedEvent
);
431 nCellModifiedEvent
= nullptr;
432 LINK( this, EditBrowseBox
, CellModifiedHdl
).Call( nullptr );
435 if (rEvt
.GetColumnId() == HandleColumnId
)
436 { // it was the handle column. save the current cell content if necessary
437 // (clicking on the handle column results in selecting the current row)
438 if (IsEditing() && aController
->IsValueChangedFromSaved())
442 aMouseEvent
.Set(&rEvt
,true);
443 BrowseBox::MouseButtonDown(rEvt
);
446 if (m_nBrowserFlags
& EditBrowseBoxFlags::ACTIVATE_ON_BUTTONDOWN
)
448 // the base class does not travel upon MouseButtonDown, but implActivateCellOnMouseEvent assumes we traveled ...
449 GoToRowColumnId( rEvt
.GetRow(), rEvt
.GetColumnId() );
450 if (rEvt
.GetRow() >= 0)
451 implActivateCellOnMouseEvent(rEvt
, false);
455 void EditBrowseBox::MouseButtonUp( const BrowserMouseEvent
& rEvt
)
457 // absorb double clicks
458 if (rEvt
.GetClicks() > 1 && rEvt
.GetRow() >= 0)
461 aMouseEvent
.Set(&rEvt
,false);
462 BrowseBox::MouseButtonUp(rEvt
);
465 if (!(m_nBrowserFlags
& EditBrowseBoxFlags::ACTIVATE_ON_BUTTONDOWN
))
466 if (rEvt
.GetRow() >= 0)
467 implActivateCellOnMouseEvent(rEvt
, true);
470 bool EditBrowseBox::ControlHasFocus() const
472 Window
* pControlWindow
= aController
? &aController
->GetWindow() : nullptr;
473 if (ControlBase
* pControlBase
= dynamic_cast<ControlBase
*>(pControlWindow
))
474 return pControlBase
->ControlHasFocus();
475 return pControlWindow
&& pControlWindow
->HasChildPathFocus();
478 void EditBrowseBox::implActivateCellOnMouseEvent(const BrowserMouseEvent
& _rEvt
, bool _bUp
)
482 else if (IsEditing() && !aController
->GetWindow().IsEnabled())
484 else if (IsEditing() && !ControlHasFocus())
487 if (!IsEditing() || !aController
->GetWindow().IsEnabled())
490 // forwards the event to the control
491 aController
->ActivatingMouseEvent(_rEvt
, _bUp
);
494 void EditBrowseBox::Dispatch( sal_uInt16 _nId
)
496 if ( _nId
== BROWSER_ENHANCESELECTION
)
497 { // this is a workaround for the bug in the base class:
498 // if the row selection is to be extended (which is what BROWSER_ENHANCESELECTION tells us)
499 // then the base class does not revert any column selections, while, for doing a "simple"
500 // selection (BROWSER_SELECT), it does. In fact, it does not only revert the col selection then,
501 // but also any current row selections.
502 // This clearly tells me that the both ids are for row selection only - there this behaviour does
504 // But here, where we have column selection, too, we take care of this ourself.
505 if ( GetSelectColumnCount( ) )
507 while ( GetSelectColumnCount( ) )
509 sal::static_int_cast
< sal_uInt16
>(FirstSelectedColumn()),
514 BrowseBox::Dispatch( _nId
);
517 bool EditBrowseBox::ProcessKey(const KeyEvent
& rKeyEvent
)
519 sal_uInt16 nCode
= rKeyEvent
.GetKeyCode().GetCode();
520 bool bShift
= rKeyEvent
.GetKeyCode().IsShift();
521 bool bCtrl
= rKeyEvent
.GetKeyCode().IsMod1();
522 bool bAlt
= rKeyEvent
.GetKeyCode().IsMod2();
523 bool bLocalSelect
= false;
524 bool bNonEditOnly
= false;
525 sal_uInt16 nId
= BROWSER_NONE
;
527 if (!bAlt
&& !bCtrl
&& !bShift
)
530 case KEY_DOWN
: nId
= BROWSER_CURSORDOWN
; break;
531 case KEY_UP
: nId
= BROWSER_CURSORUP
; break;
532 case KEY_PAGEDOWN
: nId
= BROWSER_CURSORPAGEDOWN
; break;
533 case KEY_PAGEUP
: nId
= BROWSER_CURSORPAGEUP
; break;
534 case KEY_HOME
: nId
= BROWSER_CURSORHOME
; break;
535 case KEY_END
: nId
= BROWSER_CURSOREND
; break;
538 // ask if traveling to the next cell is allowed
539 if (IsTabAllowed(true))
540 nId
= BROWSER_CURSORRIGHT
;
544 // save the cell content (if necessary)
545 if (IsEditing() && aController
->IsValueChangedFromSaved() && !SaveModified())
547 // maybe we're not visible ...
549 aController
->GetWindow().GrabFocus();
552 // ask if traveling to the next cell is allowed
553 if (IsTabAllowed(true))
554 nId
= BROWSER_CURSORRIGHT
;
557 case KEY_RIGHT
: nId
= BROWSER_CURSORRIGHT
; break;
558 case KEY_LEFT
: nId
= BROWSER_CURSORLEFT
; break;
559 case KEY_SPACE
: nId
= BROWSER_SELECT
; bNonEditOnly
= bLocalSelect
= true; break;
562 if ( !bAlt
&& !bCtrl
&& bShift
)
565 case KEY_DOWN
: nId
= BROWSER_SELECTDOWN
; bLocalSelect
= true; break;
566 case KEY_UP
: nId
= BROWSER_SELECTUP
; bLocalSelect
= true; break;
567 case KEY_HOME
: nId
= BROWSER_SELECTHOME
; bLocalSelect
= true; break;
568 case KEY_END
: nId
= BROWSER_SELECTEND
; bLocalSelect
= true; break;
570 if (IsTabAllowed(false))
571 nId
= BROWSER_CURSORLEFT
;
575 if ( !bAlt
&& bCtrl
&& bShift
)
578 case KEY_SPACE
: nId
= BROWSER_SELECTCOLUMN
; bLocalSelect
= true; break;
582 if ( !bAlt
&& bCtrl
&& !bShift
)
585 case KEY_DOWN
: nId
= BROWSER_SCROLLUP
; break;
586 case KEY_UP
: nId
= BROWSER_SCROLLDOWN
; break;
587 case KEY_PAGEDOWN
: nId
= BROWSER_CURSORENDOFFILE
; break;
588 case KEY_PAGEUP
: nId
= BROWSER_CURSORTOPOFFILE
; break;
589 case KEY_HOME
: nId
= BROWSER_CURSORTOPOFSCREEN
; break;
590 case KEY_END
: nId
= BROWSER_CURSORENDOFSCREEN
; break;
591 case KEY_SPACE
: nId
= BROWSER_ENHANCESELECTION
; bLocalSelect
= true; break;
595 if ( ( nId
!= BROWSER_NONE
)
598 && aController
->MoveAllowed(rKeyEvent
)
603 if (nId
== BROWSER_SELECT
|| BROWSER_SELECTCOLUMN
== nId
)
605 // save the cell content (if necessary)
606 if (IsEditing() && aController
->IsValueChangedFromSaved() && !SaveModified())
608 // maybe we're not visible ...
610 aController
->GetWindow().GrabFocus();
617 if (bLocalSelect
&& (GetSelectRowCount() || GetSelection() != nullptr))
624 bool EditBrowseBox::PreNotify(NotifyEvent
& rEvt
)
626 if (rEvt
.GetType() == NotifyEventType::KEYINPUT
)
628 if ( (IsEditing() && ControlHasFocus())
629 || rEvt
.GetWindow() == &GetDataWindow()
630 || (!IsEditing() && HasChildPathFocus())
633 if (ProcessKey(*rEvt
.GetKeyEvent()))
637 return BrowseBox::PreNotify(rEvt
);
640 bool EditBrowseBox::IsTabAllowed(bool) const
646 bool EditBrowseBox::EventNotify(NotifyEvent
& rEvt
)
648 switch (rEvt
.GetType())
650 case NotifyEventType::GETFOCUS
:
651 DetermineFocus(getRealGetFocusFlags(this));
654 case NotifyEventType::LOSEFOCUS
:
661 return BrowseBox::EventNotify(rEvt
);
665 void EditBrowseBox::StateChanged( StateChangedType nType
)
667 BrowseBox::StateChanged( nType
);
669 bool bNeedCellReActivation
= false;
670 if ( nType
== StateChangedType::Mirroring
)
672 bNeedCellReActivation
= true;
674 else if ( nType
== StateChangedType::Zoom
)
676 ImplInitSettings( true, false, false );
677 bNeedCellReActivation
= true;
679 else if ( nType
== StateChangedType::ControlFont
)
681 ImplInitSettings( true, false, false );
684 else if ( nType
== StateChangedType::ControlForeground
)
686 ImplInitSettings( false, true, false );
689 else if ( nType
== StateChangedType::ControlBackground
)
691 ImplInitSettings( false, false, true );
694 else if (nType
== StateChangedType::Style
)
696 WinBits nStyle
= GetStyle();
697 if (!(nStyle
& WB_NOTABSTOP
) )
698 nStyle
|= WB_TABSTOP
;
702 if ( bNeedCellReActivation
)
713 void EditBrowseBox::DataChanged( const DataChangedEvent
& rDCEvt
)
715 BrowseBox::DataChanged( rDCEvt
);
717 if ((( rDCEvt
.GetType() == DataChangedEventType::SETTINGS
) ||
718 ( rDCEvt
.GetType() == DataChangedEventType::DISPLAY
)) &&
719 ( rDCEvt
.GetFlags() & AllSettingsFlags::STYLE
))
721 ImplInitSettings( true, true, true );
726 void EditBrowseBox::ImplInitSettings( bool bFont
, bool bForeground
, bool bBackground
)
728 const StyleSettings
& rStyleSettings
= GetSettings().GetStyleSettings();
732 vcl::Font aFont
= rStyleSettings
.GetFieldFont();
735 GetDataWindow().SetControlFont(GetControlFont());
736 aFont
.Merge(GetControlFont());
739 GetDataWindow().SetControlFont();
741 GetDataWindow().SetZoomedPointFont(*GetDataWindow().GetOutDev(), aFont
);
744 if (bFont
|| bForeground
)
746 Color aTextColor
= rStyleSettings
.GetFieldTextColor();
747 if (IsControlForeground())
749 aTextColor
= GetControlForeground();
750 GetDataWindow().SetControlForeground(aTextColor
);
753 GetDataWindow().SetControlForeground();
755 GetDataWindow().SetTextColor( aTextColor
);
758 if (!bBackground
) // FIXME: Outside of Paint Hierarchy
761 if (GetDataWindow().IsControlBackground())
763 GetDataWindow().SetControlBackground(GetControlBackground());
764 GetDataWindow().SetBackground(GetDataWindow().GetControlBackground());
765 GetDataWindow().GetOutDev()->SetFillColor(GetDataWindow().GetControlBackground());
769 GetDataWindow().SetControlBackground();
770 GetDataWindow().SetBackground(rStyleSettings
.GetFieldColor());
771 GetDataWindow().GetOutDev()->SetFillColor(rStyleSettings
.GetFieldColor());
776 bool EditBrowseBox::IsCursorMoveAllowed(sal_Int32 nNewRow
, sal_uInt16 nNewColId
) const
778 sal_uInt16 nInfo
= 0;
780 if (GetSelectColumnCount() || (aMouseEvent
.Is() && aMouseEvent
->GetRow() < 0))
782 if ((GetSelection() != nullptr && GetSelectRowCount()) ||
783 (aMouseEvent
.Is() && aMouseEvent
->GetColumnId() == HandleColumnId
))
785 if (!nInfo
&& nNewRow
!= nEditRow
)
787 if (!nInfo
&& nNewColId
!= nEditCol
)
790 if (nInfo
== 0) // nothing happened
793 // save the cell content
794 if (IsEditing() && aController
->IsValueChangedFromSaved() && !const_cast<EditBrowseBox
*>(this)->SaveModified())
796 // maybe we're not visible ...
798 aController
->GetWindow().GrabFocus();
802 EditBrowseBox
* pTHIS
= const_cast<EditBrowseBox
*> (this);
804 // save the cell content if
805 // a) a selection is being made
806 // b) the row is changing
807 if (IsModified() && (nInfo
& (ROWCHANGE
| COLSELECT
| ROWSELECT
)) &&
810 if (nInfo
& COLSELECT
||
814 pTHIS
->SetNoSelection();
819 if (!Controller()->GetWindow().IsVisible())
823 aController
->GetWindow().GrabFocus();
828 if (nNewRow
!= nEditRow
)
830 vcl::Window
& rWindow
= GetDataWindow();
831 if ((nEditRow
>= 0) && !(GetBrowserFlags() & EditBrowseBoxFlags::NO_HANDLE_COLUMN_CONTENT
))
833 tools::Rectangle aRect
= GetFieldRectPixel(nEditRow
, 0, false );
834 // status cell should be painted if and only if text is displayed
835 pTHIS
->bPaintStatus
= ( GetBrowserFlags() & EditBrowseBoxFlags::HANDLE_COLUMN_TEXT
) == EditBrowseBoxFlags::HANDLE_COLUMN_TEXT
;
836 rWindow
.Invalidate(aRect
);
837 pTHIS
->bPaintStatus
= true;
840 // don't paint during row change
841 rWindow
.EnablePaint(false);
843 // the last veto chance for derived classes
844 if (!pTHIS
->CursorMoving(nNewRow
, nNewColId
))
846 pTHIS
->InvalidateStatusCell(nEditRow
);
847 rWindow
.EnablePaint(true);
852 rWindow
.EnablePaint(true);
857 return pTHIS
->CursorMoving(nNewRow
, nNewColId
);
861 void EditBrowseBox::ColumnMoved(sal_uInt16 nId
)
863 BrowseBox::ColumnMoved(nId
);
866 tools::Rectangle
aRect( GetCellRect(nEditRow
, nEditCol
, false));
867 CellControllerRef aControllerRef
= Controller();
868 ResizeController(aControllerRef
, aRect
);
869 Controller()->GetWindow().GrabFocus();
874 bool EditBrowseBox::SaveRow()
880 bool EditBrowseBox::CursorMoving(sal_Int32
, sal_uInt16
)
882 DeactivateCell(false);
887 void EditBrowseBox::CursorMoved()
889 sal_Int32 nNewRow
= GetCurRow();
890 if (nEditRow
!= nNewRow
)
892 if (!(GetBrowserFlags() & EditBrowseBoxFlags::NO_HANDLE_COLUMN_CONTENT
))
893 InvalidateStatusCell(nNewRow
);
897 GetDataWindow().EnablePaint(true);
898 // should not be called here because the descant event is not needed here
899 //BrowseBox::CursorMoved();
903 void EditBrowseBox::EndScroll()
907 tools::Rectangle aRect
= GetCellRect(nEditRow
, nEditCol
, false);
908 ResizeController(aController
,aRect
);
911 BrowseBox::EndScroll();
915 void EditBrowseBox::ActivateCell(sal_Int32 nRow
, sal_uInt16 nCol
, bool bCellFocus
)
922 if ((GetSelectRowCount() && GetSelection() != nullptr) || GetSelectColumnCount() ||
923 (aMouseEvent
.Is() && (aMouseEvent
.IsDown() || aMouseEvent
->GetClicks() > 1))) // nothing happens on MouseDown
928 if (nEditRow
< 0 || nEditCol
<= HandleColumnId
)
931 aController
= GetController(nRow
, nCol
);
932 if (aController
.is())
934 tools::Rectangle
aRect( GetCellRect(nEditRow
, nEditCol
, false));
935 ResizeController(aController
, aRect
);
937 InitController(aController
, nEditRow
, nEditCol
);
939 aController
->SaveValue();
940 aController
->SetModifyHdl(LINK(this,EditBrowseBox
,ModifyHdl
));
943 if ( isAccessibleAlive() )
944 implCreateActiveAccessible();
946 // activate the cell only of the browser has the focus
947 if ( bHasFocus
&& bCellFocus
)
952 // no controller -> we have a new "active descendant"
953 if ( isAccessibleAlive() && HasFocus() )
956 ACTIVE_DESCENDANT_CHANGED
,
957 Any( CreateAccessibleCell( nRow
, GetColumnPos( nCol
-1) ) ),
965 void EditBrowseBox::DeactivateCell(bool bUpdate
)
970 if ( isAccessibleAlive() )
972 commitBrowseBoxEvent( CHILD
, Any(), Any( m_aImpl
->m_xActiveCell
) );
973 m_aImpl
->clearActiveCell();
976 aOldController
= aController
;
979 // reset the modify handler
980 aOldController
->SetModifyHdl(Link
<LinkParamNone
*,void>());
983 GrabFocus(); // ensure that we have (and keep) the focus
985 aOldController
->suspend();
987 // update if requested
991 // release the controller (asynchronously)
993 Application::RemoveUserEvent(nEndEvent
);
994 nEndEvent
= Application::PostUserEvent(LINK(this,EditBrowseBox
,EndEditHdl
), nullptr, true);
998 tools::Rectangle
EditBrowseBox::GetCellRect(sal_Int32 nRow
, sal_uInt16 nColId
, bool bRel
) const
1000 tools::Rectangle
aRect( GetFieldRectPixel(nRow
, nColId
, bRel
));
1001 if ((GetMode() & BrowserMode::CURSOR_WO_FOCUS
) == BrowserMode::CURSOR_WO_FOCUS
)
1003 aRect
.AdjustTop(1 );
1004 aRect
.AdjustBottom( -1 );
1010 IMPL_LINK_NOARG(EditBrowseBox
, EndEditHdl
, void*, void)
1012 nEndEvent
= nullptr;
1014 aOldController
= CellControllerRef();
1018 IMPL_LINK_NOARG(EditBrowseBox
, ModifyHdl
, LinkParamNone
*, void)
1020 if (nCellModifiedEvent
)
1021 Application::RemoveUserEvent(nCellModifiedEvent
);
1022 nCellModifiedEvent
= Application::PostUserEvent(LINK(this,EditBrowseBox
,CellModifiedHdl
), nullptr, true);
1026 IMPL_LINK_NOARG(EditBrowseBox
, CellModifiedHdl
, void*, void)
1028 nCellModifiedEvent
= nullptr;
1032 void EditBrowseBox::ColumnResized( sal_uInt16
)
1036 tools::Rectangle
aRect( GetCellRect(nEditRow
, nEditCol
, false));
1037 CellControllerRef aControllerRef
= Controller();
1038 ResizeController(aControllerRef
, aRect
);
1039 // don't grab focus if Field Properties panel is being
1040 // resized by split pane drag resizing
1041 if (Application::IsUICaptured())
1043 Controller()->GetWindow().GrabFocus();
1047 sal_uInt16
EditBrowseBox::AppendColumn(const OUString
& rName
, sal_uInt16 nWidth
, sal_uInt16 nPos
, sal_uInt16 nId
)
1049 if (nId
== BROWSER_INVALIDID
)
1051 // look for the next free id
1052 for (nId
= ColCount(); nId
> 0 && GetColumnPos(nId
) != BROWSER_INVALIDID
; nId
--)
1057 // if there is no handle column
1059 if ( ColCount() == 0 || GetColumnId(0) != HandleColumnId
)
1060 nId
= ColCount() + 1;
1064 DBG_ASSERT(nId
, "EditBrowseBox::AppendColumn: invalid id!");
1066 tools::Long w
= nWidth
;
1068 w
= GetDefaultColumnWidth(rName
);
1070 InsertDataColumn(nId
, rName
, w
, (HeaderBarItemBits::CENTER
| HeaderBarItemBits::CLICKABLE
), nPos
);
1074 void EditBrowseBox::Resize()
1076 BrowseBox::Resize();
1078 // if the window is smaller than "title line height" + "control area",
1080 if (GetOutputSizePixel().Height() <
1081 (GetControlArea().GetHeight() + GetDataWindow().GetPosPixel().Y()))
1084 // the size of the control area
1085 Point
aPoint(GetControlArea().TopLeft());
1086 sal_uInt16 nX
= static_cast<sal_uInt16
>(aPoint
.X());
1088 ArrangeControls(nX
, static_cast<sal_uInt16
>(aPoint
.Y()));
1093 bool bChanged
= ReserveControlArea(nX
);
1095 //tdf#97731 if the reserved area changed size, give the controls a
1096 //chance to adapt to the new size
1099 nX
= static_cast<sal_uInt16
>(aPoint
.X());
1100 ArrangeControls(nX
, static_cast<sal_uInt16
>(aPoint
.Y()));
1104 void EditBrowseBox::ArrangeControls(sal_uInt16
&, sal_uInt16
)
1108 CellController
* EditBrowseBox::GetController(sal_Int32
, sal_uInt16
)
1113 void EditBrowseBox::ResizeController(CellControllerRef
const & rController
, const tools::Rectangle
& rRect
)
1115 Point
aPoint(rRect
.TopLeft());
1116 Size
aSize(rRect
.GetSize());
1117 Control
& rControl
= rController
->GetWindow();
1118 auto nMinHeight
= rControl
.get_preferred_size().Height();
1119 if (nMinHeight
> aSize
.Height())
1121 auto nOffset
= (nMinHeight
- aSize
.Height()) / 2;
1122 aPoint
.AdjustY(-nOffset
);
1123 aSize
.setHeight(nMinHeight
);
1125 rControl
.SetPosSizePixel(aPoint
, aSize
);
1128 void EditBrowseBox::InitController(CellControllerRef
&, sal_Int32
, sal_uInt16
)
1133 void EditBrowseBox::CellModified()
1138 bool EditBrowseBox::SaveModified()
1144 void EditBrowseBox::DoubleClick(const BrowserMouseEvent
& rEvt
)
1146 // when double clicking on the column, the optimum size will be calculated
1147 sal_uInt16 nColId
= rEvt
.GetColumnId();
1148 if (nColId
!= HandleColumnId
)
1149 SetColumnWidth(nColId
, GetAutoColumnWidth(nColId
));
1153 sal_uInt32
EditBrowseBox::GetAutoColumnWidth(sal_uInt16 nColId
)
1155 sal_uInt32 nCurColWidth
= GetColumnWidth(nColId
);
1156 sal_uInt32 nMinColWidth
= CalcZoom(20); // minimum
1157 sal_uInt32 nNewColWidth
= nMinColWidth
;
1158 sal_Int32 nMaxRows
= std::min(sal_Int32(GetVisibleRows()), GetRowCount());
1159 sal_Int32 nLastVisRow
= GetTopRow() + nMaxRows
- 1;
1161 if (GetTopRow() <= nLastVisRow
) // calc the column with using the cell contents
1163 for (tools::Long i
= GetTopRow(); i
<= nLastVisRow
; ++i
)
1164 nNewColWidth
= std::max(nNewColWidth
,GetTotalCellWidth(i
,nColId
) + 12);
1166 if (nNewColWidth
== nCurColWidth
) // size has not changed
1167 nNewColWidth
= GetDefaultColumnWidth(GetColumnTitle(nColId
));
1170 nNewColWidth
= GetDefaultColumnWidth(GetColumnTitle(nColId
));
1171 return nNewColWidth
;
1174 sal_uInt32
EditBrowseBox::GetTotalCellWidth(sal_Int32
, sal_uInt16
)
1179 void EditBrowseBox::InvalidateHandleColumn()
1181 tools::Rectangle
aHdlFieldRect( GetFieldRectPixel( 0, 0 ));
1182 tools::Rectangle
aInvalidRect( Point(0,0), GetOutputSizePixel() );
1183 aInvalidRect
.SetRight( aHdlFieldRect
.Right() );
1184 Invalidate( aInvalidRect
);
1187 void EditBrowseBox::PaintTristate(const tools::Rectangle
& rRect
, const TriState
& eState
, bool _bEnabled
) const
1189 pCheckBoxPaint
->SetState(eState
);
1191 pCheckBoxPaint
->GetBox().set_sensitive(_bEnabled
);
1193 Size aBoxSize
= pCheckBoxPaint
->GetBox().get_preferred_size();
1194 tools::Rectangle
aRect(Point(rRect
.Left() + ((rRect
.GetWidth() - aBoxSize
.Width()) / 2),
1195 rRect
.Top() + ((rRect
.GetHeight() - aBoxSize
.Height()) / 2)),
1197 pCheckBoxPaint
->SetPosSizePixel(aRect
.TopLeft(), aRect
.GetSize());
1199 pCheckBoxPaint
->Draw(GetDataWindow().GetOutDev(), aRect
.TopLeft(), SystemTextColorFlags::NONE
);
1202 void EditBrowseBox::AsynchGetFocus()
1205 Application::RemoveUserEvent(nStartEvent
);
1207 m_pFocusWhileRequest
= Application::GetFocusWindow();
1208 nStartEvent
= Application::PostUserEvent(LINK(this,EditBrowseBox
,StartEditHdl
), nullptr, true);
1212 void EditBrowseBox::SetBrowserFlags(EditBrowseBoxFlags nFlags
)
1214 if (m_nBrowserFlags
== nFlags
)
1217 bool RowPicturesChanges
= ((m_nBrowserFlags
& EditBrowseBoxFlags::NO_HANDLE_COLUMN_CONTENT
) !=
1218 (nFlags
& EditBrowseBoxFlags::NO_HANDLE_COLUMN_CONTENT
));
1219 m_nBrowserFlags
= nFlags
;
1221 if (RowPicturesChanges
)
1222 InvalidateStatusCell(GetCurRow());
1225 inline void EditBrowseBox::EnableAndShow() const
1227 Controller()->resume();
1230 CellController::CellController(ControlBase
* pW
)
1232 , bSuspended( true )
1235 DBG_ASSERT(pWindow
, "CellController::CellController: missing the window!");
1236 DBG_ASSERT(!pWindow
->IsVisible(), "CellController::CellController: window should not be visible!");
1239 CellController::~CellController()
1243 void CellController::suspend( )
1245 DBG_ASSERT( bSuspended
== !GetWindow().IsVisible(), "CellController::suspend: inconsistence!" );
1246 if ( !isSuspended( ) )
1248 CommitModifications();
1249 GetWindow().Hide( );
1250 GetWindow().Disable( );
1255 void CellController::resume( )
1257 DBG_ASSERT( bSuspended
== !GetWindow().IsVisible(), "CellController::resume: inconsistence!" );
1258 if ( isSuspended( ) )
1260 GetWindow().Enable( );
1261 GetWindow().Show( );
1266 void CellController::CommitModifications()
1268 // nothing to do in this base class
1271 void CellController::ActivatingMouseEvent(const BrowserMouseEvent
& /*rEvt*/, bool /*bUp*/)
1273 // nothing to do in this base class
1276 bool CellController::MoveAllowed(const KeyEvent
&) const
1284 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */