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::accessibility
;
54 using namespace ::com::sun::star::uno
;
58 IEditImplementation::~IEditImplementation()
64 void EditBrowserHeader::DoubleClick()
66 sal_uInt16 nColId
= GetCurItemId();
69 tools::Long nAutoWidth
= static_cast<EditBrowseBox
*>(GetParent())->GetAutoColumnWidth(nColId
);
70 if (nAutoWidth
!= static_cast<EditBrowseBox
*>(GetParent())->GetColumnWidth(nColId
))
72 static_cast<EditBrowseBox
*>(GetParent())->SetColumnWidth(nColId
, nAutoWidth
);
73 static_cast<EditBrowseBox
*>(GetParent())->ColumnResized(nColId
);
80 void EditBrowseBox::BrowserMouseEventPtr::Clear()
85 void EditBrowseBox::BrowserMouseEventPtr::Set(const BrowserMouseEvent
* pEvt
, bool bIsDown
)
87 if (pEvt
== pEvent
.get())
95 pEvent
.reset(new BrowserMouseEvent(pEvt
->GetWindow(),
105 EditBrowseBox::EditBrowseBox( vcl::Window
* pParent
, EditBrowseBoxFlags nBrowserFlags
, WinBits nBits
, BrowserMode _nMode
)
106 :BrowseBox( pParent
, nBits
, _nMode
)
107 ,nStartEvent(nullptr)
109 ,nCellModifiedEvent(nullptr)
110 ,m_pFocusWhileRequest(nullptr)
116 ,bActiveBeforeTracking( false )
117 ,m_nBrowserFlags(nBrowserFlags
)
120 m_aImpl
.reset(new EditBrowseBoxImpl
);
122 SetCompoundControl(true);
124 ImplInitSettings(true, true, true);
126 pCheckBoxPaint
= VclPtr
<CheckBoxControl
>::Create(&GetDataWindow());
127 pCheckBoxPaint
->SetPaintTransparent( true );
128 pCheckBoxPaint
->SetBackground();
131 void EditBrowseBox::Init()
136 EditBrowseBox::~EditBrowseBox()
141 void EditBrowseBox::dispose()
144 Application::RemoveUserEvent(nStartEvent
);
146 Application::RemoveUserEvent(nEndEvent
);
147 if (nCellModifiedEvent
)
148 Application::RemoveUserEvent(nCellModifiedEvent
);
150 pCheckBoxPaint
.disposeAndClear();
151 m_pFocusWhileRequest
.clear();
153 BrowseBox::dispose();
157 void EditBrowseBox::RemoveRows()
160 nEditRow
= nPaintRow
= -1;
164 VclPtr
<BrowserHeader
> EditBrowseBox::CreateHeaderBar(BrowseBox
* pParent
)
166 pHeader
= imp_CreateHeaderBar(pParent
);
168 pHeader
->SetUpdateMode(false);
172 VclPtr
<BrowserHeader
> EditBrowseBox::imp_CreateHeaderBar(BrowseBox
* pParent
)
174 return VclPtr
<EditBrowserHeader
>::Create(pParent
);
177 void EditBrowseBox::LoseFocus()
179 BrowseBox::LoseFocus();
183 void EditBrowseBox::GetFocus()
185 BrowseBox::GetFocus();
187 // This should handle the case that the BrowseBox (or one of its children)
188 // gets the focus from outside by pressing Tab
189 if (IsEditing() && Controller()->GetWindow().IsVisible())
190 Controller()->GetWindow().GrabFocus();
192 DetermineFocus(getRealGetFocusFlags(this));
195 bool EditBrowseBox::SeekRow(sal_Int32 nRow
)
201 IMPL_LINK_NOARG(EditBrowseBox
, StartEditHdl
, void*, void)
203 nStartEvent
= nullptr;
207 if (!ControlHasFocus() && (m_pFocusWhileRequest
.get() == Application::GetFocusWindow()))
208 aController
->GetWindow().GrabFocus();
212 void EditBrowseBox::PaintField( vcl::RenderContext
& rDev
, const tools::Rectangle
& rRect
,
213 sal_uInt16 nColumnId
) const
215 if (nColumnId
== HandleColumnId
)
218 PaintStatusCell(rDev
, rRect
);
222 // don't paint the current cell
223 if (rDev
.GetOwnerWindow() == &GetDataWindow())
224 // but only if we're painting onto our data win (which is the usual painting)
225 if (nPaintRow
== nEditRow
)
227 if (IsEditing() && nEditCol
== nColumnId
&& aController
->GetWindow().IsVisible())
230 PaintCell(rDev
, rRect
, nColumnId
);
234 Image
EditBrowseBox::GetImage(RowStatus eStatus
) const
237 bool bNeedMirror
= IsRTLEnabled();
241 aBitmap
= BitmapEx(BMP_CURRENT
);
244 aBitmap
= BitmapEx(BMP_CURRENTNEW
);
247 aBitmap
= BitmapEx(BMP_MODIFIED
);
248 bNeedMirror
= false; // the pen is not mirrored
251 aBitmap
= BitmapEx(BMP_NEW
);
254 aBitmap
= BitmapEx(BMP_DELETED
);
257 aBitmap
= BitmapEx(BMP_PRIMARYKEY
);
259 case CURRENT_PRIMARYKEY
:
260 aBitmap
= BitmapEx(BMP_CURRENT_PRIMARYKEY
);
263 aBitmap
= BitmapEx(BMP_FILTER
);
266 aBitmap
= BitmapEx(BMP_HEADERFOOTER
);
273 aBitmap
.Mirror( BmpMirrorFlags::Horizontal
);
275 return Image(aBitmap
);
278 void EditBrowseBox::PaintStatusCell(OutputDevice
& rDev
, const tools::Rectangle
& rRect
) const
283 RowStatus eStatus
= GetRowStatus( nPaintRow
);
284 EditBrowseBoxFlags nBrowserFlags
= GetBrowserFlags();
286 if (nBrowserFlags
& EditBrowseBoxFlags::NO_HANDLE_COLUMN_CONTENT
)
289 // draw the text of the header column
290 if (nBrowserFlags
& EditBrowseBoxFlags::HANDLE_COLUMN_TEXT
)
292 rDev
.DrawText( rRect
, GetCellText( nPaintRow
, 0 ),
293 DrawTextFlags::Center
| DrawTextFlags::VCenter
| DrawTextFlags::Clip
);
296 else if (eStatus
!= CLEAN
&& rDev
.GetOutDevType() == OUTDEV_WINDOW
)
298 Image
aImage(GetImage(eStatus
));
299 // calc the image position
300 Size
aImageSize(aImage
.GetSizePixel());
301 aImageSize
.setWidth( CalcZoom(aImageSize
.Width()) );
302 aImageSize
.setHeight( CalcZoom(aImageSize
.Height()) );
303 Point
aPos( rRect
.TopLeft() );
305 if ( ( aImageSize
.Width() > rRect
.GetWidth() ) || ( aImageSize
.Height() > rRect
.GetHeight() ) )
306 rDev
.SetClipRegion(vcl::Region(rRect
));
308 if ( aImageSize
.Width() < rRect
.GetWidth() )
309 aPos
.AdjustX(( rRect
.GetWidth() - aImageSize
.Width() ) / 2 );
311 if ( aImageSize
.Height() < rRect
.GetHeight() )
312 aPos
.AdjustY(( rRect
.GetHeight() - aImageSize
.Height() ) / 2 );
315 rDev
.DrawImage( aPos
, aImageSize
, aImage
);
317 rDev
.DrawImage( aPos
, aImage
);
319 if (rDev
.IsClipRegion())
320 rDev
.SetClipRegion();
325 void EditBrowseBox::ImplStartTracking()
327 bActiveBeforeTracking
= IsEditing();
328 if ( bActiveBeforeTracking
)
334 BrowseBox::ImplStartTracking();
338 void EditBrowseBox::ImplEndTracking()
340 if ( bActiveBeforeTracking
)
342 bActiveBeforeTracking
= false;
344 BrowseBox::ImplEndTracking();
348 void EditBrowseBox::RowHeightChanged()
352 tools::Rectangle
aRect( GetCellRect( nEditRow
, nEditCol
, false ) );
353 CellControllerRef
aCellController( Controller() );
354 ResizeController( aCellController
, aRect
);
355 aCellController
->GetWindow().GrabFocus();
358 BrowseBox::RowHeightChanged();
362 EditBrowseBox::RowStatus
EditBrowseBox::GetRowStatus(sal_Int32
) const
368 void EditBrowseBox::KeyInput( const KeyEvent
& rEvt
)
370 sal_uInt16 nCode
= rEvt
.GetKeyCode().GetCode();
371 bool bShift
= rEvt
.GetKeyCode().IsShift();
372 bool bCtrl
= rEvt
.GetKeyCode().IsMod1();
377 if (!bCtrl
&& !bShift
&& IsTabAllowed(true))
379 Dispatch(BROWSER_CURSORRIGHT
);
382 BrowseBox::KeyInput(rEvt
);
385 if (!bCtrl
&& !bShift
)
387 if (IsTabAllowed(true))
388 Dispatch(BROWSER_CURSORRIGHT
);
390 // do NOT call BrowseBox::KeyInput : this would handle the tab, but we already now
391 // that tab isn't allowed here. So give the Control class a chance
392 Control::KeyInput(rEvt
);
395 else if (!bCtrl
&& bShift
)
397 if (IsTabAllowed(false))
398 Dispatch(BROWSER_CURSORLEFT
);
400 // do NOT call BrowseBox::KeyInput : this would handle the tab, but we already now
401 // that tab isn't allowed here. So give the Control class a chance
402 Control::KeyInput(rEvt
);
407 BrowseBox::KeyInput(rEvt
);
411 void EditBrowseBox::ChildFocusIn()
413 DetermineFocus(getRealGetFocusFlags(this));
416 void EditBrowseBox::ChildFocusOut()
421 void EditBrowseBox::MouseButtonDown(const BrowserMouseEvent
& rEvt
)
423 // absorb double clicks
424 if (rEvt
.GetClicks() > 1 && rEvt
.GetRow() >= 0)
427 // we are about to leave the current cell. If there is a "this cell has been modified" notification
428 // pending (asynchronously), this may be deadly -> do it synchronously
429 if ( nCellModifiedEvent
)
431 Application::RemoveUserEvent( nCellModifiedEvent
);
432 nCellModifiedEvent
= nullptr;
433 LINK( this, EditBrowseBox
, CellModifiedHdl
).Call( nullptr );
436 if (rEvt
.GetColumnId() == HandleColumnId
)
437 { // it was the handle column. save the current cell content if necessary
438 // (clicking on the handle column results in selecting the current row)
439 if (IsEditing() && aController
->IsValueChangedFromSaved())
443 aMouseEvent
.Set(&rEvt
,true);
444 BrowseBox::MouseButtonDown(rEvt
);
447 if (m_nBrowserFlags
& EditBrowseBoxFlags::ACTIVATE_ON_BUTTONDOWN
)
449 // the base class does not travel upon MouseButtonDown, but implActivateCellOnMouseEvent assumes we traveled ...
450 GoToRowColumnId( rEvt
.GetRow(), rEvt
.GetColumnId() );
451 if (rEvt
.GetRow() >= 0)
452 implActivateCellOnMouseEvent(rEvt
, false);
456 void EditBrowseBox::MouseButtonUp( const BrowserMouseEvent
& rEvt
)
458 // absorb double clicks
459 if (rEvt
.GetClicks() > 1 && rEvt
.GetRow() >= 0)
462 aMouseEvent
.Set(&rEvt
,false);
463 BrowseBox::MouseButtonUp(rEvt
);
466 if (!(m_nBrowserFlags
& EditBrowseBoxFlags::ACTIVATE_ON_BUTTONDOWN
))
467 if (rEvt
.GetRow() >= 0)
468 implActivateCellOnMouseEvent(rEvt
, true);
471 bool EditBrowseBox::ControlHasFocus() const
473 Window
* pControlWindow
= aController
? &aController
->GetWindow() : nullptr;
474 if (ControlBase
* pControlBase
= dynamic_cast<ControlBase
*>(pControlWindow
))
475 return pControlBase
->ControlHasFocus();
476 return pControlWindow
&& pControlWindow
->HasChildPathFocus();
479 void EditBrowseBox::implActivateCellOnMouseEvent(const BrowserMouseEvent
& _rEvt
, bool _bUp
)
483 else if (IsEditing() && !aController
->GetWindow().IsEnabled())
485 else if (IsEditing() && !ControlHasFocus())
488 if (!IsEditing() || !aController
->GetWindow().IsEnabled())
491 // forwards the event to the control
492 aController
->ActivatingMouseEvent(_rEvt
, _bUp
);
495 void EditBrowseBox::Dispatch( sal_uInt16 _nId
)
497 if ( _nId
== BROWSER_ENHANCESELECTION
)
498 { // this is a workaround for the bug in the base class:
499 // if the row selection is to be extended (which is what BROWSER_ENHANCESELECTION tells us)
500 // then the base class does not revert any column selections, while, for doing a "simple"
501 // selection (BROWSER_SELECT), it does. In fact, it does not only revert the col selection then,
502 // but also any current row selections.
503 // This clearly tells me that the both ids are for row selection only - there this behaviour does
505 // But here, where we have column selection, too, we take care of this ourself.
506 if ( GetSelectColumnCount( ) )
508 while ( GetSelectColumnCount( ) )
510 sal::static_int_cast
< sal_uInt16
>(FirstSelectedColumn()),
515 BrowseBox::Dispatch( _nId
);
518 bool EditBrowseBox::ProcessKey(const KeyEvent
& rKeyEvent
)
520 sal_uInt16 nCode
= rKeyEvent
.GetKeyCode().GetCode();
521 bool bShift
= rKeyEvent
.GetKeyCode().IsShift();
522 bool bCtrl
= rKeyEvent
.GetKeyCode().IsMod1();
523 bool bAlt
= rKeyEvent
.GetKeyCode().IsMod2();
524 bool bLocalSelect
= false;
525 bool bNonEditOnly
= false;
526 sal_uInt16 nId
= BROWSER_NONE
;
528 if (!bAlt
&& !bCtrl
&& !bShift
)
531 case KEY_DOWN
: nId
= BROWSER_CURSORDOWN
; break;
532 case KEY_UP
: nId
= BROWSER_CURSORUP
; break;
533 case KEY_PAGEDOWN
: nId
= BROWSER_CURSORPAGEDOWN
; break;
534 case KEY_PAGEUP
: nId
= BROWSER_CURSORPAGEUP
; break;
535 case KEY_HOME
: nId
= BROWSER_CURSORHOME
; break;
536 case KEY_END
: nId
= BROWSER_CURSOREND
; break;
539 // ask if traveling to the next cell is allowed
540 if (IsTabAllowed(true))
541 nId
= BROWSER_CURSORRIGHT
;
545 // save the cell content (if necessary)
546 if (IsEditing() && aController
->IsValueChangedFromSaved() && !SaveModified())
548 // maybe we're not visible ...
550 aController
->GetWindow().GrabFocus();
553 // ask if traveling to the next cell is allowed
554 if (IsTabAllowed(true))
555 nId
= BROWSER_CURSORRIGHT
;
558 case KEY_RIGHT
: nId
= BROWSER_CURSORRIGHT
; break;
559 case KEY_LEFT
: nId
= BROWSER_CURSORLEFT
; break;
560 case KEY_SPACE
: nId
= BROWSER_SELECT
; bNonEditOnly
= bLocalSelect
= true; break;
563 if ( !bAlt
&& !bCtrl
&& bShift
)
566 case KEY_DOWN
: nId
= BROWSER_SELECTDOWN
; bLocalSelect
= true; break;
567 case KEY_UP
: nId
= BROWSER_SELECTUP
; bLocalSelect
= true; break;
568 case KEY_HOME
: nId
= BROWSER_SELECTHOME
; bLocalSelect
= true; break;
569 case KEY_END
: nId
= BROWSER_SELECTEND
; bLocalSelect
= true; break;
571 if (IsTabAllowed(false))
572 nId
= BROWSER_CURSORLEFT
;
576 if ( !bAlt
&& bCtrl
&& bShift
)
579 case KEY_SPACE
: nId
= BROWSER_SELECTCOLUMN
; bLocalSelect
= true; break;
583 if ( !bAlt
&& bCtrl
&& !bShift
)
586 case KEY_DOWN
: nId
= BROWSER_SCROLLUP
; break;
587 case KEY_UP
: nId
= BROWSER_SCROLLDOWN
; break;
588 case KEY_PAGEDOWN
: nId
= BROWSER_CURSORENDOFFILE
; break;
589 case KEY_PAGEUP
: nId
= BROWSER_CURSORTOPOFFILE
; break;
590 case KEY_HOME
: nId
= BROWSER_CURSORTOPOFSCREEN
; break;
591 case KEY_END
: nId
= BROWSER_CURSORENDOFSCREEN
; break;
592 case KEY_SPACE
: nId
= BROWSER_ENHANCESELECTION
; bLocalSelect
= true; break;
596 if ( ( nId
!= BROWSER_NONE
)
599 && aController
->MoveAllowed(rKeyEvent
)
604 if (nId
== BROWSER_SELECT
|| BROWSER_SELECTCOLUMN
== nId
)
606 // save the cell content (if necessary)
607 if (IsEditing() && aController
->IsValueChangedFromSaved() && !SaveModified())
609 // maybe we're not visible ...
611 aController
->GetWindow().GrabFocus();
618 if (bLocalSelect
&& (GetSelectRowCount() || GetSelection() != nullptr))
625 bool EditBrowseBox::PreNotify(NotifyEvent
& rEvt
)
627 if (rEvt
.GetType() == NotifyEventType::KEYINPUT
)
629 if ( (IsEditing() && ControlHasFocus())
630 || rEvt
.GetWindow() == &GetDataWindow()
631 || (!IsEditing() && HasChildPathFocus())
634 if (ProcessKey(*rEvt
.GetKeyEvent()))
638 return BrowseBox::PreNotify(rEvt
);
641 bool EditBrowseBox::IsTabAllowed(bool) const
647 bool EditBrowseBox::EventNotify(NotifyEvent
& rEvt
)
649 switch (rEvt
.GetType())
651 case NotifyEventType::GETFOCUS
:
652 DetermineFocus(getRealGetFocusFlags(this));
655 case NotifyEventType::LOSEFOCUS
:
662 return BrowseBox::EventNotify(rEvt
);
666 void EditBrowseBox::StateChanged( StateChangedType nType
)
668 BrowseBox::StateChanged( nType
);
670 bool bNeedCellReActivation
= false;
671 if ( nType
== StateChangedType::Mirroring
)
673 bNeedCellReActivation
= true;
675 else if ( nType
== StateChangedType::Zoom
)
677 ImplInitSettings( true, false, false );
678 bNeedCellReActivation
= true;
680 else if ( nType
== StateChangedType::ControlFont
)
682 ImplInitSettings( true, false, false );
685 else if ( nType
== StateChangedType::ControlForeground
)
687 ImplInitSettings( false, true, false );
690 else if ( nType
== StateChangedType::ControlBackground
)
692 ImplInitSettings( false, false, true );
695 else if (nType
== StateChangedType::Style
)
697 WinBits nStyle
= GetStyle();
698 if (!(nStyle
& WB_NOTABSTOP
) )
699 nStyle
|= WB_TABSTOP
;
703 if ( bNeedCellReActivation
)
714 void EditBrowseBox::DataChanged( const DataChangedEvent
& rDCEvt
)
716 BrowseBox::DataChanged( rDCEvt
);
718 if ((( rDCEvt
.GetType() == DataChangedEventType::SETTINGS
) ||
719 ( rDCEvt
.GetType() == DataChangedEventType::DISPLAY
)) &&
720 ( rDCEvt
.GetFlags() & AllSettingsFlags::STYLE
))
722 ImplInitSettings( true, true, true );
727 void EditBrowseBox::ImplInitSettings( bool bFont
, bool bForeground
, bool bBackground
)
729 const StyleSettings
& rStyleSettings
= GetSettings().GetStyleSettings();
733 vcl::Font aFont
= rStyleSettings
.GetFieldFont();
736 GetDataWindow().SetControlFont(GetControlFont());
737 aFont
.Merge(GetControlFont());
740 GetDataWindow().SetControlFont();
742 GetDataWindow().SetZoomedPointFont(*GetDataWindow().GetOutDev(), aFont
);
745 if (bFont
|| bForeground
)
747 Color aTextColor
= rStyleSettings
.GetFieldTextColor();
748 if (IsControlForeground())
750 aTextColor
= GetControlForeground();
751 GetDataWindow().SetControlForeground(aTextColor
);
754 GetDataWindow().SetControlForeground();
756 GetDataWindow().SetTextColor( aTextColor
);
759 if (!bBackground
) // FIXME: Outside of Paint Hierarchy
762 if (GetDataWindow().IsControlBackground())
764 GetDataWindow().SetControlBackground(GetControlBackground());
765 GetDataWindow().SetBackground(GetDataWindow().GetControlBackground());
766 GetDataWindow().GetOutDev()->SetFillColor(GetDataWindow().GetControlBackground());
770 GetDataWindow().SetControlBackground();
771 GetDataWindow().SetBackground(rStyleSettings
.GetFieldColor());
772 GetDataWindow().GetOutDev()->SetFillColor(rStyleSettings
.GetFieldColor());
777 bool EditBrowseBox::IsCursorMoveAllowed(sal_Int32 nNewRow
, sal_uInt16 nNewColId
) const
779 sal_uInt16 nInfo
= 0;
781 if (GetSelectColumnCount() || (aMouseEvent
.Is() && aMouseEvent
->GetRow() < 0))
783 if ((GetSelection() != nullptr && GetSelectRowCount()) ||
784 (aMouseEvent
.Is() && aMouseEvent
->GetColumnId() == HandleColumnId
))
786 if (!nInfo
&& nNewRow
!= nEditRow
)
788 if (!nInfo
&& nNewColId
!= nEditCol
)
791 if (nInfo
== 0) // nothing happened
794 // save the cell content
795 if (IsEditing() && aController
->IsValueChangedFromSaved() && !const_cast<EditBrowseBox
*>(this)->SaveModified())
797 // maybe we're not visible ...
799 aController
->GetWindow().GrabFocus();
803 EditBrowseBox
* pTHIS
= const_cast<EditBrowseBox
*> (this);
805 // save the cell content if
806 // a) a selection is being made
807 // b) the row is changing
808 if (IsModified() && (nInfo
& (ROWCHANGE
| COLSELECT
| ROWSELECT
)) &&
811 if (nInfo
& COLSELECT
||
815 pTHIS
->SetNoSelection();
820 if (!Controller()->GetWindow().IsVisible())
824 aController
->GetWindow().GrabFocus();
829 if (nNewRow
!= nEditRow
)
831 vcl::Window
& rWindow
= GetDataWindow();
832 if ((nEditRow
>= 0) && !(GetBrowserFlags() & EditBrowseBoxFlags::NO_HANDLE_COLUMN_CONTENT
))
834 tools::Rectangle aRect
= GetFieldRectPixel(nEditRow
, 0, false );
835 // status cell should be painted if and only if text is displayed
836 pTHIS
->bPaintStatus
= ( GetBrowserFlags() & EditBrowseBoxFlags::HANDLE_COLUMN_TEXT
) == EditBrowseBoxFlags::HANDLE_COLUMN_TEXT
;
837 rWindow
.Invalidate(aRect
);
838 pTHIS
->bPaintStatus
= true;
841 // don't paint during row change
842 rWindow
.EnablePaint(false);
844 // the last veto chance for derived classes
845 if (!pTHIS
->CursorMoving(nNewRow
, nNewColId
))
847 pTHIS
->InvalidateStatusCell(nEditRow
);
848 rWindow
.EnablePaint(true);
853 rWindow
.EnablePaint(true);
858 return pTHIS
->CursorMoving(nNewRow
, nNewColId
);
862 void EditBrowseBox::ColumnMoved(sal_uInt16 nId
)
864 BrowseBox::ColumnMoved(nId
);
867 tools::Rectangle
aRect( GetCellRect(nEditRow
, nEditCol
, false));
868 CellControllerRef aControllerRef
= Controller();
869 ResizeController(aControllerRef
, aRect
);
870 Controller()->GetWindow().GrabFocus();
875 bool EditBrowseBox::SaveRow()
881 bool EditBrowseBox::CursorMoving(sal_Int32
, sal_uInt16
)
883 DeactivateCell(false);
888 void EditBrowseBox::CursorMoved()
890 sal_Int32 nNewRow
= GetCurRow();
891 if (nEditRow
!= nNewRow
)
893 if (!(GetBrowserFlags() & EditBrowseBoxFlags::NO_HANDLE_COLUMN_CONTENT
))
894 InvalidateStatusCell(nNewRow
);
898 GetDataWindow().EnablePaint(true);
899 // should not be called here because the descant event is not needed here
900 //BrowseBox::CursorMoved();
904 void EditBrowseBox::EndScroll()
908 tools::Rectangle aRect
= GetCellRect(nEditRow
, nEditCol
, false);
909 ResizeController(aController
,aRect
);
912 BrowseBox::EndScroll();
916 void EditBrowseBox::ActivateCell(sal_Int32 nRow
, sal_uInt16 nCol
, bool bCellFocus
)
923 if ((GetSelectRowCount() && GetSelection() != nullptr) || GetSelectColumnCount() ||
924 (aMouseEvent
.Is() && (aMouseEvent
.IsDown() || aMouseEvent
->GetClicks() > 1))) // nothing happens on MouseDown
929 if (nEditRow
< 0 || nEditCol
<= HandleColumnId
)
932 aController
= GetController(nRow
, nCol
);
933 if (aController
.is())
935 tools::Rectangle
aRect( GetCellRect(nEditRow
, nEditCol
, false));
936 ResizeController(aController
, aRect
);
938 InitController(aController
, nEditRow
, nEditCol
);
940 aController
->SaveValue();
941 aController
->SetModifyHdl(LINK(this,EditBrowseBox
,ModifyHdl
));
944 if ( isAccessibleAlive() )
945 implCreateActiveAccessible();
947 // activate the cell only of the browser has the focus
948 if ( bHasFocus
&& bCellFocus
)
953 // no controller -> we have a new "active descendant"
954 if ( isAccessibleAlive() && HasFocus() )
957 AccessibleEventId::ACTIVE_DESCENDANT_CHANGED
,
958 Any( CreateAccessibleCell( nRow
, GetColumnPos( nCol
-1) ) ),
966 void EditBrowseBox::DeactivateCell(bool bUpdate
)
971 if ( isAccessibleAlive() && m_aImpl
->m_xActiveCell
)
973 commitBrowseBoxEvent(AccessibleEventId::CHILD
, Any(), Any(m_aImpl
->m_xActiveCell
));
974 m_aImpl
->clearActiveCell();
977 aOldController
= aController
;
980 // reset the modify handler
981 aOldController
->SetModifyHdl(Link
<LinkParamNone
*,void>());
984 GrabFocus(); // ensure that we have (and keep) the focus
986 aOldController
->suspend();
988 // update if requested
992 // release the controller (asynchronously)
994 Application::RemoveUserEvent(nEndEvent
);
995 nEndEvent
= Application::PostUserEvent(LINK(this,EditBrowseBox
,EndEditHdl
), nullptr, true);
999 tools::Rectangle
EditBrowseBox::GetCellRect(sal_Int32 nRow
, sal_uInt16 nColId
, bool bRel
) const
1001 tools::Rectangle
aRect( GetFieldRectPixel(nRow
, nColId
, bRel
));
1002 if ((GetMode() & BrowserMode::CURSOR_WO_FOCUS
) == BrowserMode::CURSOR_WO_FOCUS
)
1004 aRect
.AdjustTop(1 );
1005 aRect
.AdjustBottom( -1 );
1011 IMPL_LINK_NOARG(EditBrowseBox
, EndEditHdl
, void*, void)
1013 nEndEvent
= nullptr;
1015 aOldController
= CellControllerRef();
1019 IMPL_LINK_NOARG(EditBrowseBox
, ModifyHdl
, LinkParamNone
*, void)
1021 if (nCellModifiedEvent
)
1022 Application::RemoveUserEvent(nCellModifiedEvent
);
1023 nCellModifiedEvent
= Application::PostUserEvent(LINK(this,EditBrowseBox
,CellModifiedHdl
), nullptr, true);
1027 IMPL_LINK_NOARG(EditBrowseBox
, CellModifiedHdl
, void*, void)
1029 nCellModifiedEvent
= nullptr;
1033 void EditBrowseBox::ColumnResized( sal_uInt16
)
1037 tools::Rectangle
aRect( GetCellRect(nEditRow
, nEditCol
, false));
1038 CellControllerRef aControllerRef
= Controller();
1039 ResizeController(aControllerRef
, aRect
);
1040 // don't grab focus if Field Properties panel is being
1041 // resized by split pane drag resizing
1042 if (Application::IsUICaptured())
1044 Controller()->GetWindow().GrabFocus();
1048 sal_uInt16
EditBrowseBox::AppendColumn(const OUString
& rName
, sal_uInt16 nWidth
, sal_uInt16 nPos
, sal_uInt16 nId
)
1050 if (nId
== BROWSER_INVALIDID
)
1052 // look for the next free id
1053 for (nId
= ColCount(); nId
> 0 && GetColumnPos(nId
) != BROWSER_INVALIDID
; nId
--)
1058 // if there is no handle column
1060 if ( ColCount() == 0 || GetColumnId(0) != HandleColumnId
)
1061 nId
= ColCount() + 1;
1065 DBG_ASSERT(nId
, "EditBrowseBox::AppendColumn: invalid id!");
1067 tools::Long w
= nWidth
;
1069 w
= GetDefaultColumnWidth(rName
);
1071 InsertDataColumn(nId
, rName
, w
, (HeaderBarItemBits::CENTER
| HeaderBarItemBits::CLICKABLE
), nPos
);
1075 void EditBrowseBox::Resize()
1077 BrowseBox::Resize();
1079 // if the window is smaller than "title line height" + "control area",
1081 if (GetOutputSizePixel().Height() <
1082 (GetControlArea().GetHeight() + GetDataWindow().GetPosPixel().Y()))
1085 // the size of the control area
1086 Point
aPoint(GetControlArea().TopLeft());
1087 sal_uInt16 nX
= static_cast<sal_uInt16
>(aPoint
.X());
1089 ArrangeControls(nX
, static_cast<sal_uInt16
>(aPoint
.Y()));
1094 bool bChanged
= ReserveControlArea(nX
);
1096 //tdf#97731 if the reserved area changed size, give the controls a
1097 //chance to adapt to the new size
1100 nX
= static_cast<sal_uInt16
>(aPoint
.X());
1101 ArrangeControls(nX
, static_cast<sal_uInt16
>(aPoint
.Y()));
1105 void EditBrowseBox::ArrangeControls(sal_uInt16
&, sal_uInt16
)
1109 CellController
* EditBrowseBox::GetController(sal_Int32
, sal_uInt16
)
1114 void EditBrowseBox::ResizeController(CellControllerRef
const & rController
, const tools::Rectangle
& rRect
)
1116 Point
aPoint(rRect
.TopLeft());
1117 Size
aSize(rRect
.GetSize());
1118 Control
& rControl
= rController
->GetWindow();
1119 auto nMinHeight
= rControl
.get_preferred_size().Height();
1120 if (nMinHeight
> aSize
.Height())
1122 auto nOffset
= (nMinHeight
- aSize
.Height()) / 2;
1123 aPoint
.AdjustY(-nOffset
);
1124 aSize
.setHeight(nMinHeight
);
1126 rControl
.SetPosSizePixel(aPoint
, aSize
);
1129 void EditBrowseBox::InitController(CellControllerRef
&, sal_Int32
, sal_uInt16
)
1134 void EditBrowseBox::CellModified()
1139 bool EditBrowseBox::SaveModified()
1145 void EditBrowseBox::DoubleClick(const BrowserMouseEvent
& rEvt
)
1147 // when double clicking on the column, the optimum size will be calculated
1148 sal_uInt16 nColId
= rEvt
.GetColumnId();
1149 if (nColId
!= HandleColumnId
)
1150 SetColumnWidth(nColId
, GetAutoColumnWidth(nColId
));
1154 sal_uInt32
EditBrowseBox::GetAutoColumnWidth(sal_uInt16 nColId
)
1156 sal_uInt32 nCurColWidth
= GetColumnWidth(nColId
);
1157 sal_uInt32 nMinColWidth
= CalcZoom(20); // minimum
1158 sal_uInt32 nNewColWidth
= nMinColWidth
;
1159 sal_Int32 nMaxRows
= std::min(sal_Int32(GetVisibleRows()), GetRowCount());
1160 sal_Int32 nLastVisRow
= GetTopRow() + nMaxRows
- 1;
1162 if (GetTopRow() <= nLastVisRow
) // calc the column with using the cell contents
1164 for (tools::Long i
= GetTopRow(); i
<= nLastVisRow
; ++i
)
1165 nNewColWidth
= std::max(nNewColWidth
,GetTotalCellWidth(i
,nColId
) + 12);
1167 if (nNewColWidth
== nCurColWidth
) // size has not changed
1168 nNewColWidth
= GetDefaultColumnWidth(GetColumnTitle(nColId
));
1171 nNewColWidth
= GetDefaultColumnWidth(GetColumnTitle(nColId
));
1172 return nNewColWidth
;
1175 sal_uInt32
EditBrowseBox::GetTotalCellWidth(sal_Int32
, sal_uInt16
)
1180 void EditBrowseBox::InvalidateHandleColumn()
1182 tools::Rectangle
aHdlFieldRect( GetFieldRectPixel( 0, 0 ));
1183 tools::Rectangle
aInvalidRect( Point(0,0), GetOutputSizePixel() );
1184 aInvalidRect
.SetRight( aHdlFieldRect
.Right() );
1185 Invalidate( aInvalidRect
);
1188 void EditBrowseBox::PaintTristate(const tools::Rectangle
& rRect
, const TriState
& eState
, bool _bEnabled
) const
1190 pCheckBoxPaint
->SetState(eState
);
1192 pCheckBoxPaint
->GetBox().set_sensitive(_bEnabled
);
1194 Size aBoxSize
= pCheckBoxPaint
->GetBox().get_preferred_size();
1195 tools::Rectangle
aRect(Point(rRect
.Left() + ((rRect
.GetWidth() - aBoxSize
.Width()) / 2),
1196 rRect
.Top() + ((rRect
.GetHeight() - aBoxSize
.Height()) / 2)),
1198 pCheckBoxPaint
->SetPosSizePixel(aRect
.TopLeft(), aRect
.GetSize());
1200 pCheckBoxPaint
->Draw(GetDataWindow().GetOutDev(), aRect
.TopLeft(), SystemTextColorFlags::NONE
);
1203 void EditBrowseBox::AsynchGetFocus()
1206 Application::RemoveUserEvent(nStartEvent
);
1208 m_pFocusWhileRequest
= Application::GetFocusWindow();
1209 nStartEvent
= Application::PostUserEvent(LINK(this,EditBrowseBox
,StartEditHdl
), nullptr, true);
1213 void EditBrowseBox::SetBrowserFlags(EditBrowseBoxFlags nFlags
)
1215 if (m_nBrowserFlags
== nFlags
)
1218 bool RowPicturesChanges
= ((m_nBrowserFlags
& EditBrowseBoxFlags::NO_HANDLE_COLUMN_CONTENT
) !=
1219 (nFlags
& EditBrowseBoxFlags::NO_HANDLE_COLUMN_CONTENT
));
1220 m_nBrowserFlags
= nFlags
;
1222 if (RowPicturesChanges
)
1223 InvalidateStatusCell(GetCurRow());
1226 inline void EditBrowseBox::EnableAndShow() const
1228 Controller()->resume();
1231 CellController::CellController(ControlBase
* pW
)
1233 , bSuspended( true )
1236 DBG_ASSERT(pWindow
, "CellController::CellController: missing the window!");
1237 DBG_ASSERT(!pWindow
->IsVisible(), "CellController::CellController: window should not be visible!");
1240 CellController::~CellController()
1244 void CellController::suspend( )
1246 DBG_ASSERT( bSuspended
== !GetWindow().IsVisible(), "CellController::suspend: inconsistence!" );
1247 if ( !isSuspended( ) )
1249 CommitModifications();
1250 GetWindow().Hide( );
1251 GetWindow().Disable( );
1256 void CellController::resume( )
1258 DBG_ASSERT( bSuspended
== !GetWindow().IsVisible(), "CellController::resume: inconsistence!" );
1259 if ( isSuspended( ) )
1261 GetWindow().Enable( );
1262 GetWindow().Show( );
1267 void CellController::CommitModifications()
1269 // nothing to do in this base class
1272 void CellController::ActivatingMouseEvent(const BrowserMouseEvent
& /*rEvt*/, bool /*bUp*/)
1274 // nothing to do in this base class
1277 bool CellController::MoveAllowed(const KeyEvent
&) const
1285 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */