tdf#130857 qt weld: Implement QtInstanceWidget::get_text_height
[LibreOffice.git] / svtools / source / brwbox / editbrowsebox.cxx
bloba86fe61c22b8d85e8b1345ae2dc19bdf4644fde1
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <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>
30 #include <algorithm>
31 #include "editbrowseboximpl.hxx"
32 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
35 namespace svt
38 namespace
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();
49 return nFlags;
53 using namespace com::sun::star::accessibility;
54 using namespace ::com::sun::star::uno;
58 IEditImplementation::~IEditImplementation()
62 //= EditBrowserHeader
64 void EditBrowserHeader::DoubleClick()
66 sal_uInt16 nColId = GetCurItemId();
67 if (nColId)
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);
78 //= EditBrowseBox
80 void EditBrowseBox::BrowserMouseEventPtr::Clear()
82 pEvent.reset();
85 void EditBrowseBox::BrowserMouseEventPtr::Set(const BrowserMouseEvent* pEvt, bool bIsDown)
87 if (pEvt == pEvent.get())
89 bDown = bIsDown;
90 return;
92 pEvent.reset();
93 if (pEvt)
95 pEvent.reset(new BrowserMouseEvent(pEvt->GetWindow(),
96 *pEvt,
97 pEvt->GetRow(),
98 pEvt->GetColumn(),
99 pEvt->GetColumnId(),
100 pEvt->GetRect()));
101 bDown = bIsDown;
105 EditBrowseBox::EditBrowseBox( vcl::Window* pParent, EditBrowseBoxFlags nBrowserFlags, WinBits nBits, BrowserMode _nMode )
106 :BrowseBox( pParent, nBits, _nMode )
107 ,nStartEvent(nullptr)
108 ,nEndEvent(nullptr)
109 ,nCellModifiedEvent(nullptr)
110 ,m_pFocusWhileRequest(nullptr)
111 ,nPaintRow(-1)
112 ,nEditRow(-1)
113 ,nEditCol(0)
114 ,bHasFocus(false)
115 ,bPaintStatus(true)
116 ,bActiveBeforeTracking( false )
117 ,m_nBrowserFlags(nBrowserFlags)
118 ,pHeader(nullptr)
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()
133 // late construction
136 EditBrowseBox::~EditBrowseBox()
138 disposeOnce();
141 void EditBrowseBox::dispose()
143 if (nStartEvent)
144 Application::RemoveUserEvent(nStartEvent);
145 if (nEndEvent)
146 Application::RemoveUserEvent(nEndEvent);
147 if (nCellModifiedEvent)
148 Application::RemoveUserEvent(nCellModifiedEvent);
150 pCheckBoxPaint.disposeAndClear();
151 m_pFocusWhileRequest.clear();
152 pHeader.clear();
153 BrowseBox::dispose();
157 void EditBrowseBox::RemoveRows()
159 BrowseBox::Clear();
160 nEditRow = nPaintRow = -1;
161 nEditCol = 0;
164 VclPtr<BrowserHeader> EditBrowseBox::CreateHeaderBar(BrowseBox* pParent)
166 pHeader = imp_CreateHeaderBar(pParent);
167 if (!IsUpdateMode())
168 pHeader->SetUpdateMode(false);
169 return pHeader;
172 VclPtr<BrowserHeader> EditBrowseBox::imp_CreateHeaderBar(BrowseBox* pParent)
174 return VclPtr<EditBrowserHeader>::Create(pParent);
177 void EditBrowseBox::LoseFocus()
179 BrowseBox::LoseFocus();
180 DetermineFocus();
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)
197 nPaintRow = nRow;
198 return true;
201 IMPL_LINK_NOARG(EditBrowseBox, StartEditHdl, void*, void)
203 nStartEvent = nullptr;
204 if (IsEditing())
206 EnableAndShow();
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)
217 if (bPaintStatus)
218 PaintStatusCell(rDev, rRect);
220 else
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())
228 return;
230 PaintCell(rDev, rRect, nColumnId);
234 Image EditBrowseBox::GetImage(RowStatus eStatus) const
236 BitmapEx aBitmap;
237 bool bNeedMirror = IsRTLEnabled();
238 switch (eStatus)
240 case CURRENT:
241 aBitmap = BitmapEx(BMP_CURRENT);
242 break;
243 case CURRENTNEW:
244 aBitmap = BitmapEx(BMP_CURRENTNEW);
245 break;
246 case MODIFIED:
247 aBitmap = BitmapEx(BMP_MODIFIED);
248 bNeedMirror = false; // the pen is not mirrored
249 break;
250 case NEW:
251 aBitmap = BitmapEx(BMP_NEW);
252 break;
253 case DELETED:
254 aBitmap = BitmapEx(BMP_DELETED);
255 break;
256 case PRIMARYKEY:
257 aBitmap = BitmapEx(BMP_PRIMARYKEY);
258 break;
259 case CURRENT_PRIMARYKEY:
260 aBitmap = BitmapEx(BMP_CURRENT_PRIMARYKEY);
261 break;
262 case FILTER:
263 aBitmap = BitmapEx(BMP_FILTER);
264 break;
265 case HEADERFOOTER:
266 aBitmap = BitmapEx(BMP_HEADERFOOTER);
267 break;
268 case CLEAN:
269 break;
271 if ( bNeedMirror )
273 aBitmap.Mirror( BmpMirrorFlags::Horizontal );
275 return Image(aBitmap);
278 void EditBrowseBox::PaintStatusCell(OutputDevice& rDev, const tools::Rectangle& rRect) const
280 if (nPaintRow < 0)
281 return;
283 RowStatus eStatus = GetRowStatus( nPaintRow );
284 EditBrowseBoxFlags nBrowserFlags = GetBrowserFlags();
286 if (nBrowserFlags & EditBrowseBoxFlags::NO_HANDLE_COLUMN_CONTENT)
287 return;
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 );
295 // draw an image
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 );
314 if ( IsZoom() )
315 rDev.DrawImage( aPos, aImageSize, aImage );
316 else
317 rDev.DrawImage( aPos, aImage );
319 if (rDev.IsClipRegion())
320 rDev.SetClipRegion();
325 void EditBrowseBox::ImplStartTracking()
327 bActiveBeforeTracking = IsEditing();
328 if ( bActiveBeforeTracking )
330 DeactivateCell();
331 PaintImmediately();
334 BrowseBox::ImplStartTracking();
338 void EditBrowseBox::ImplEndTracking()
340 if ( bActiveBeforeTracking )
341 ActivateCell();
342 bActiveBeforeTracking = false;
344 BrowseBox::ImplEndTracking();
348 void EditBrowseBox::RowHeightChanged()
350 if ( IsEditing() )
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
364 return CLEAN;
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();
374 switch (nCode)
376 case KEY_RETURN:
377 if (!bCtrl && !bShift && IsTabAllowed(true))
379 Dispatch(BROWSER_CURSORRIGHT);
381 else
382 BrowseBox::KeyInput(rEvt);
383 return;
384 case KEY_TAB:
385 if (!bCtrl && !bShift)
387 if (IsTabAllowed(true))
388 Dispatch(BROWSER_CURSORRIGHT);
389 else
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);
393 return;
395 else if (!bCtrl && bShift)
397 if (IsTabAllowed(false))
398 Dispatch(BROWSER_CURSORLEFT);
399 else
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);
403 return;
405 [[fallthrough]];
406 default:
407 BrowseBox::KeyInput(rEvt);
411 void EditBrowseBox::ChildFocusIn()
413 DetermineFocus(getRealGetFocusFlags(this));
416 void EditBrowseBox::ChildFocusOut()
418 DetermineFocus();
421 void EditBrowseBox::MouseButtonDown(const BrowserMouseEvent& rEvt)
423 // absorb double clicks
424 if (rEvt.GetClicks() > 1 && rEvt.GetRow() >= 0)
425 return;
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())
440 SaveModified();
443 aMouseEvent.Set(&rEvt,true);
444 BrowseBox::MouseButtonDown(rEvt);
445 aMouseEvent.Clear();
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)
460 return;
462 aMouseEvent.Set(&rEvt,false);
463 BrowseBox::MouseButtonUp(rEvt);
464 aMouseEvent.Clear();
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)
481 if (!IsEditing())
482 ActivateCell();
483 else if (IsEditing() && !aController->GetWindow().IsEnabled())
484 DeactivateCell();
485 else if (IsEditing() && !ControlHasFocus())
486 AsynchGetFocus();
488 if (!IsEditing() || !aController->GetWindow().IsEnabled())
489 return;
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
504 // make sense.
505 // But here, where we have column selection, too, we take care of this ourself.
506 if ( GetSelectColumnCount( ) )
508 while ( GetSelectColumnCount( ) )
509 SelectColumnPos(
510 sal::static_int_cast< sal_uInt16 >(FirstSelectedColumn()),
511 false );
512 Select();
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 )
529 switch ( nCode )
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;
538 case KEY_TAB:
539 // ask if traveling to the next cell is allowed
540 if (IsTabAllowed(true))
541 nId = BROWSER_CURSORRIGHT;
542 break;
544 case KEY_RETURN:
545 // save the cell content (if necessary)
546 if (IsEditing() && aController->IsValueChangedFromSaved() && !SaveModified())
548 // maybe we're not visible ...
549 EnableAndShow();
550 aController->GetWindow().GrabFocus();
551 return true;
553 // ask if traveling to the next cell is allowed
554 if (IsTabAllowed(true))
555 nId = BROWSER_CURSORRIGHT;
557 break;
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 )
564 switch ( nCode )
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;
570 case KEY_TAB:
571 if (IsTabAllowed(false))
572 nId = BROWSER_CURSORLEFT;
573 break;
576 if ( !bAlt && bCtrl && bShift )
577 switch ( nCode )
579 case KEY_SPACE: nId = BROWSER_SELECTCOLUMN; bLocalSelect = true; break;
583 if ( !bAlt && bCtrl && !bShift )
584 switch ( nCode )
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 )
597 && ( !IsEditing()
598 || ( !bNonEditOnly
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 ...
610 EnableAndShow();
611 aController->GetWindow().GrabFocus();
612 return true;
616 Dispatch(nId);
618 if (bLocalSelect && (GetSelectRowCount() || GetSelection() != nullptr))
619 DeactivateCell();
620 return true;
622 return false;
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()))
635 return true;
638 return BrowseBox::PreNotify(rEvt);
641 bool EditBrowseBox::IsTabAllowed(bool) const
643 return true;
647 bool EditBrowseBox::EventNotify(NotifyEvent& rEvt)
649 switch (rEvt.GetType())
651 case NotifyEventType::GETFOCUS:
652 DetermineFocus(getRealGetFocusFlags(this));
653 break;
655 case NotifyEventType::LOSEFOCUS:
656 DetermineFocus();
657 break;
659 default:
660 break;
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 );
683 Invalidate();
685 else if ( nType == StateChangedType::ControlForeground )
687 ImplInitSettings( false, true, false );
688 Invalidate();
690 else if ( nType == StateChangedType::ControlBackground )
692 ImplInitSettings( false, false, true );
693 Invalidate();
695 else if (nType == StateChangedType::Style)
697 WinBits nStyle = GetStyle();
698 if (!(nStyle & WB_NOTABSTOP) )
699 nStyle |= WB_TABSTOP;
701 SetStyle(nStyle);
703 if ( bNeedCellReActivation )
705 if ( IsEditing() )
707 DeactivateCell();
708 ActivateCell();
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 );
723 Invalidate();
727 void EditBrowseBox::ImplInitSettings( bool bFont, bool bForeground, bool bBackground )
729 const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
731 if (bFont)
733 vcl::Font aFont = rStyleSettings.GetFieldFont();
734 if (IsControlFont())
736 GetDataWindow().SetControlFont(GetControlFont());
737 aFont.Merge(GetControlFont());
739 else
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);
753 else
754 GetDataWindow().SetControlForeground();
756 GetDataWindow().SetTextColor( aTextColor );
759 if (!bBackground) // FIXME: Outside of Paint Hierarchy
760 return;
762 if (GetDataWindow().IsControlBackground())
764 GetDataWindow().SetControlBackground(GetControlBackground());
765 GetDataWindow().SetBackground(GetDataWindow().GetControlBackground());
766 GetDataWindow().GetOutDev()->SetFillColor(GetDataWindow().GetControlBackground());
768 else
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))
782 nInfo |= COLSELECT;
783 if ((GetSelection() != nullptr && GetSelectRowCount()) ||
784 (aMouseEvent.Is() && aMouseEvent->GetColumnId() == HandleColumnId))
785 nInfo |= ROWSELECT;
786 if (!nInfo && nNewRow != nEditRow)
787 nInfo |= ROWCHANGE;
788 if (!nInfo && nNewColId != nEditCol)
789 nInfo |= COLCHANGE;
791 if (nInfo == 0) // nothing happened
792 return true;
794 // save the cell content
795 if (IsEditing() && aController->IsValueChangedFromSaved() && !const_cast<EditBrowseBox *>(this)->SaveModified())
797 // maybe we're not visible ...
798 EnableAndShow();
799 aController->GetWindow().GrabFocus();
800 return false;
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)) &&
809 !pTHIS->SaveRow())
811 if (nInfo & COLSELECT ||
812 nInfo & ROWSELECT)
814 // cancel selected
815 pTHIS->SetNoSelection();
818 if (IsEditing())
820 if (!Controller()->GetWindow().IsVisible())
822 EnableAndShow();
824 aController->GetWindow().GrabFocus();
826 return false;
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);
849 return false;
851 else
853 rWindow.EnablePaint(true);
854 return true;
857 else
858 return pTHIS->CursorMoving(nNewRow, nNewColId);
862 void EditBrowseBox::ColumnMoved(sal_uInt16 nId)
864 BrowseBox::ColumnMoved(nId);
865 if (IsEditing())
867 tools::Rectangle aRect( GetCellRect(nEditRow, nEditCol, false));
868 CellControllerRef aControllerRef = Controller();
869 ResizeController(aControllerRef, aRect);
870 Controller()->GetWindow().GrabFocus();
875 bool EditBrowseBox::SaveRow()
877 return true;
881 bool EditBrowseBox::CursorMoving(sal_Int32, sal_uInt16)
883 DeactivateCell(false);
884 return true;
888 void EditBrowseBox::CursorMoved()
890 sal_Int32 nNewRow = GetCurRow();
891 if (nEditRow != nNewRow)
893 if (!(GetBrowserFlags() & EditBrowseBoxFlags::NO_HANDLE_COLUMN_CONTENT))
894 InvalidateStatusCell(nNewRow);
895 nEditRow = nNewRow;
897 ActivateCell();
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()
906 if (IsEditing())
908 tools::Rectangle aRect = GetCellRect(nEditRow, nEditCol, false);
909 ResizeController(aController,aRect);
910 AsynchGetFocus();
912 BrowseBox::EndScroll();
916 void EditBrowseBox::ActivateCell(sal_Int32 nRow, sal_uInt16 nCol, bool bCellFocus)
918 if (IsEditing())
919 return;
921 nEditCol = nCol;
923 if ((GetSelectRowCount() && GetSelection() != nullptr) || GetSelectColumnCount() ||
924 (aMouseEvent.Is() && (aMouseEvent.IsDown() || aMouseEvent->GetClicks() > 1))) // nothing happens on MouseDown
926 return;
929 if (nEditRow < 0 || nEditCol <= HandleColumnId)
930 return;
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));
942 EnableAndShow();
944 if ( isAccessibleAlive() )
945 implCreateActiveAccessible();
947 // activate the cell only of the browser has the focus
948 if ( bHasFocus && bCellFocus )
949 AsynchGetFocus();
951 else
953 // no controller -> we have a new "active descendant"
954 if ( isAccessibleAlive() && HasFocus() )
956 commitTableEvent(
957 AccessibleEventId::ACTIVE_DESCENDANT_CHANGED,
958 Any( CreateAccessibleCell( nRow, GetColumnPos( nCol -1) ) ),
959 Any()
966 void EditBrowseBox::DeactivateCell(bool bUpdate)
968 if (!IsEditing())
969 return;
971 if ( isAccessibleAlive() && m_aImpl->m_xActiveCell)
973 commitBrowseBoxEvent(AccessibleEventId::CHILD, Any(), Any(m_aImpl->m_xActiveCell));
974 m_aImpl->clearActiveCell();
977 aOldController = aController;
978 aController.clear();
980 // reset the modify handler
981 aOldController->SetModifyHdl(Link<LinkParamNone*,void>());
983 if (bHasFocus)
984 GrabFocus(); // ensure that we have (and keep) the focus
986 aOldController->suspend();
988 // update if requested
989 if (bUpdate)
990 PaintImmediately();
992 // release the controller (asynchronously)
993 if (nEndEvent)
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 );
1007 return aRect;
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;
1030 CellModified();
1033 void EditBrowseBox::ColumnResized( sal_uInt16 )
1035 if (IsEditing())
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())
1043 return;
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--)
1056 if (!nId)
1058 // if there is no handle column
1059 // increment the id
1060 if ( ColCount() == 0 || GetColumnId(0) != HandleColumnId )
1061 nId = ColCount() + 1;
1065 DBG_ASSERT(nId, "EditBrowseBox::AppendColumn: invalid id!");
1067 tools::Long w = nWidth;
1068 if (!w)
1069 w = GetDefaultColumnWidth(rName);
1071 InsertDataColumn(nId, rName, w, (HeaderBarItemBits::CENTER | HeaderBarItemBits::CLICKABLE), nPos);
1072 return nId;
1075 void EditBrowseBox::Resize()
1077 BrowseBox::Resize();
1079 // if the window is smaller than "title line height" + "control area",
1080 // do nothing
1081 if (GetOutputSizePixel().Height() <
1082 (GetControlArea().GetHeight() + GetDataWindow().GetPosPixel().Y()))
1083 return;
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()));
1091 if (!nX)
1092 nX = USHRT_MAX;
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
1098 if (bChanged)
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)
1111 return nullptr;
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()
1141 return true;
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));
1170 else
1171 nNewColWidth = GetDefaultColumnWidth(GetColumnTitle(nColId));
1172 return nNewColWidth;
1175 sal_uInt32 EditBrowseBox::GetTotalCellWidth(sal_Int32, sal_uInt16)
1177 return 0;
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)),
1197 aBoxSize);
1198 pCheckBoxPaint->SetPosSizePixel(aRect.TopLeft(), aRect.GetSize());
1200 pCheckBoxPaint->Draw(GetDataWindow().GetOutDev(), aRect.TopLeft(), SystemTextColorFlags::NONE);
1203 void EditBrowseBox::AsynchGetFocus()
1205 if (nStartEvent)
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)
1216 return;
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)
1232 : pWindow(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( );
1252 bSuspended = true;
1256 void CellController::resume( )
1258 DBG_ASSERT( bSuspended == !GetWindow().IsVisible(), "CellController::resume: inconsistence!" );
1259 if ( isSuspended( ) )
1261 GetWindow().Enable( );
1262 GetWindow().Show( );
1263 bSuspended = false;
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
1279 return true;
1282 } // namespace svt
1285 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */