Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / svtools / source / brwbox / editbrowsebox.cxx
blob46f3379b784760652389629050bd0e4f3b93be41
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::uno;
54 using namespace com::sun::star::accessibility::AccessibleEventId;
57 IEditImplementation::~IEditImplementation()
61 //= EditBrowserHeader
63 void EditBrowserHeader::DoubleClick()
65 sal_uInt16 nColId = GetCurItemId();
66 if (nColId)
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);
77 //= EditBrowseBox
79 void EditBrowseBox::BrowserMouseEventPtr::Clear()
81 pEvent.reset();
84 void EditBrowseBox::BrowserMouseEventPtr::Set(const BrowserMouseEvent* pEvt, bool bIsDown)
86 if (pEvt == pEvent.get())
88 bDown = bIsDown;
89 return;
91 pEvent.reset();
92 if (pEvt)
94 pEvent.reset(new BrowserMouseEvent(pEvt->GetWindow(),
95 *pEvt,
96 pEvt->GetRow(),
97 pEvt->GetColumn(),
98 pEvt->GetColumnId(),
99 pEvt->GetRect()));
100 bDown = bIsDown;
104 EditBrowseBox::EditBrowseBox( vcl::Window* pParent, EditBrowseBoxFlags nBrowserFlags, WinBits nBits, BrowserMode _nMode )
105 :BrowseBox( pParent, nBits, _nMode )
106 ,nStartEvent(nullptr)
107 ,nEndEvent(nullptr)
108 ,nCellModifiedEvent(nullptr)
109 ,m_pFocusWhileRequest(nullptr)
110 ,nPaintRow(-1)
111 ,nEditRow(-1)
112 ,nEditCol(0)
113 ,bHasFocus(false)
114 ,bPaintStatus(true)
115 ,bActiveBeforeTracking( false )
116 ,m_nBrowserFlags(nBrowserFlags)
117 ,pHeader(nullptr)
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()
132 // late construction
135 EditBrowseBox::~EditBrowseBox()
137 disposeOnce();
140 void EditBrowseBox::dispose()
142 if (nStartEvent)
143 Application::RemoveUserEvent(nStartEvent);
144 if (nEndEvent)
145 Application::RemoveUserEvent(nEndEvent);
146 if (nCellModifiedEvent)
147 Application::RemoveUserEvent(nCellModifiedEvent);
149 pCheckBoxPaint.disposeAndClear();
150 m_pFocusWhileRequest.clear();
151 pHeader.clear();
152 BrowseBox::dispose();
156 void EditBrowseBox::RemoveRows()
158 BrowseBox::Clear();
159 nEditRow = nPaintRow = -1;
160 nEditCol = 0;
163 VclPtr<BrowserHeader> EditBrowseBox::CreateHeaderBar(BrowseBox* pParent)
165 pHeader = imp_CreateHeaderBar(pParent);
166 if (!IsUpdateMode())
167 pHeader->SetUpdateMode(false);
168 return pHeader;
171 VclPtr<BrowserHeader> EditBrowseBox::imp_CreateHeaderBar(BrowseBox* pParent)
173 return VclPtr<EditBrowserHeader>::Create(pParent);
176 void EditBrowseBox::LoseFocus()
178 BrowseBox::LoseFocus();
179 DetermineFocus();
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)
196 nPaintRow = nRow;
197 return true;
200 IMPL_LINK_NOARG(EditBrowseBox, StartEditHdl, void*, void)
202 nStartEvent = nullptr;
203 if (IsEditing())
205 EnableAndShow();
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)
216 if (bPaintStatus)
217 PaintStatusCell(rDev, rRect);
219 else
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())
227 return;
229 PaintCell(rDev, rRect, nColumnId);
233 Image EditBrowseBox::GetImage(RowStatus eStatus) const
235 BitmapEx aBitmap;
236 bool bNeedMirror = IsRTLEnabled();
237 switch (eStatus)
239 case CURRENT:
240 aBitmap = BitmapEx(BMP_CURRENT);
241 break;
242 case CURRENTNEW:
243 aBitmap = BitmapEx(BMP_CURRENTNEW);
244 break;
245 case MODIFIED:
246 aBitmap = BitmapEx(BMP_MODIFIED);
247 bNeedMirror = false; // the pen is not mirrored
248 break;
249 case NEW:
250 aBitmap = BitmapEx(BMP_NEW);
251 break;
252 case DELETED:
253 aBitmap = BitmapEx(BMP_DELETED);
254 break;
255 case PRIMARYKEY:
256 aBitmap = BitmapEx(BMP_PRIMARYKEY);
257 break;
258 case CURRENT_PRIMARYKEY:
259 aBitmap = BitmapEx(BMP_CURRENT_PRIMARYKEY);
260 break;
261 case FILTER:
262 aBitmap = BitmapEx(BMP_FILTER);
263 break;
264 case HEADERFOOTER:
265 aBitmap = BitmapEx(BMP_HEADERFOOTER);
266 break;
267 case CLEAN:
268 break;
270 if ( bNeedMirror )
272 aBitmap.Mirror( BmpMirrorFlags::Horizontal );
274 return Image(aBitmap);
277 void EditBrowseBox::PaintStatusCell(OutputDevice& rDev, const tools::Rectangle& rRect) const
279 if (nPaintRow < 0)
280 return;
282 RowStatus eStatus = GetRowStatus( nPaintRow );
283 EditBrowseBoxFlags nBrowserFlags = GetBrowserFlags();
285 if (nBrowserFlags & EditBrowseBoxFlags::NO_HANDLE_COLUMN_CONTENT)
286 return;
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 );
294 // draw an image
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 );
313 if ( IsZoom() )
314 rDev.DrawImage( aPos, aImageSize, aImage );
315 else
316 rDev.DrawImage( aPos, aImage );
318 if (rDev.IsClipRegion())
319 rDev.SetClipRegion();
324 void EditBrowseBox::ImplStartTracking()
326 bActiveBeforeTracking = IsEditing();
327 if ( bActiveBeforeTracking )
329 DeactivateCell();
330 PaintImmediately();
333 BrowseBox::ImplStartTracking();
337 void EditBrowseBox::ImplEndTracking()
339 if ( bActiveBeforeTracking )
340 ActivateCell();
341 bActiveBeforeTracking = false;
343 BrowseBox::ImplEndTracking();
347 void EditBrowseBox::RowHeightChanged()
349 if ( IsEditing() )
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
363 return CLEAN;
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();
373 switch (nCode)
375 case KEY_RETURN:
376 if (!bCtrl && !bShift && IsTabAllowed(true))
378 Dispatch(BROWSER_CURSORRIGHT);
380 else
381 BrowseBox::KeyInput(rEvt);
382 return;
383 case KEY_TAB:
384 if (!bCtrl && !bShift)
386 if (IsTabAllowed(true))
387 Dispatch(BROWSER_CURSORRIGHT);
388 else
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);
392 return;
394 else if (!bCtrl && bShift)
396 if (IsTabAllowed(false))
397 Dispatch(BROWSER_CURSORLEFT);
398 else
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);
402 return;
404 [[fallthrough]];
405 default:
406 BrowseBox::KeyInput(rEvt);
410 void EditBrowseBox::ChildFocusIn()
412 DetermineFocus(getRealGetFocusFlags(this));
415 void EditBrowseBox::ChildFocusOut()
417 DetermineFocus();
420 void EditBrowseBox::MouseButtonDown(const BrowserMouseEvent& rEvt)
422 // absorb double clicks
423 if (rEvt.GetClicks() > 1 && rEvt.GetRow() >= 0)
424 return;
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())
439 SaveModified();
442 aMouseEvent.Set(&rEvt,true);
443 BrowseBox::MouseButtonDown(rEvt);
444 aMouseEvent.Clear();
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)
459 return;
461 aMouseEvent.Set(&rEvt,false);
462 BrowseBox::MouseButtonUp(rEvt);
463 aMouseEvent.Clear();
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)
480 if (!IsEditing())
481 ActivateCell();
482 else if (IsEditing() && !aController->GetWindow().IsEnabled())
483 DeactivateCell();
484 else if (IsEditing() && !ControlHasFocus())
485 AsynchGetFocus();
487 if (!IsEditing() || !aController->GetWindow().IsEnabled())
488 return;
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
503 // make sense.
504 // But here, where we have column selection, too, we take care of this ourself.
505 if ( GetSelectColumnCount( ) )
507 while ( GetSelectColumnCount( ) )
508 SelectColumnPos(
509 sal::static_int_cast< sal_uInt16 >(FirstSelectedColumn()),
510 false );
511 Select();
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 )
528 switch ( nCode )
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;
537 case KEY_TAB:
538 // ask if traveling to the next cell is allowed
539 if (IsTabAllowed(true))
540 nId = BROWSER_CURSORRIGHT;
541 break;
543 case KEY_RETURN:
544 // save the cell content (if necessary)
545 if (IsEditing() && aController->IsValueChangedFromSaved() && !SaveModified())
547 // maybe we're not visible ...
548 EnableAndShow();
549 aController->GetWindow().GrabFocus();
550 return true;
552 // ask if traveling to the next cell is allowed
553 if (IsTabAllowed(true))
554 nId = BROWSER_CURSORRIGHT;
556 break;
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 )
563 switch ( nCode )
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;
569 case KEY_TAB:
570 if (IsTabAllowed(false))
571 nId = BROWSER_CURSORLEFT;
572 break;
575 if ( !bAlt && bCtrl && bShift )
576 switch ( nCode )
578 case KEY_SPACE: nId = BROWSER_SELECTCOLUMN; bLocalSelect = true; break;
582 if ( !bAlt && bCtrl && !bShift )
583 switch ( nCode )
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 )
596 && ( !IsEditing()
597 || ( !bNonEditOnly
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 ...
609 EnableAndShow();
610 aController->GetWindow().GrabFocus();
611 return true;
615 Dispatch(nId);
617 if (bLocalSelect && (GetSelectRowCount() || GetSelection() != nullptr))
618 DeactivateCell();
619 return true;
621 return false;
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()))
634 return true;
637 return BrowseBox::PreNotify(rEvt);
640 bool EditBrowseBox::IsTabAllowed(bool) const
642 return true;
646 bool EditBrowseBox::EventNotify(NotifyEvent& rEvt)
648 switch (rEvt.GetType())
650 case NotifyEventType::GETFOCUS:
651 DetermineFocus(getRealGetFocusFlags(this));
652 break;
654 case NotifyEventType::LOSEFOCUS:
655 DetermineFocus();
656 break;
658 default:
659 break;
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 );
682 Invalidate();
684 else if ( nType == StateChangedType::ControlForeground )
686 ImplInitSettings( false, true, false );
687 Invalidate();
689 else if ( nType == StateChangedType::ControlBackground )
691 ImplInitSettings( false, false, true );
692 Invalidate();
694 else if (nType == StateChangedType::Style)
696 WinBits nStyle = GetStyle();
697 if (!(nStyle & WB_NOTABSTOP) )
698 nStyle |= WB_TABSTOP;
700 SetStyle(nStyle);
702 if ( bNeedCellReActivation )
704 if ( IsEditing() )
706 DeactivateCell();
707 ActivateCell();
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 );
722 Invalidate();
726 void EditBrowseBox::ImplInitSettings( bool bFont, bool bForeground, bool bBackground )
728 const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
730 if (bFont)
732 vcl::Font aFont = rStyleSettings.GetFieldFont();
733 if (IsControlFont())
735 GetDataWindow().SetControlFont(GetControlFont());
736 aFont.Merge(GetControlFont());
738 else
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);
752 else
753 GetDataWindow().SetControlForeground();
755 GetDataWindow().SetTextColor( aTextColor );
758 if (!bBackground) // FIXME: Outside of Paint Hierarchy
759 return;
761 if (GetDataWindow().IsControlBackground())
763 GetDataWindow().SetControlBackground(GetControlBackground());
764 GetDataWindow().SetBackground(GetDataWindow().GetControlBackground());
765 GetDataWindow().GetOutDev()->SetFillColor(GetDataWindow().GetControlBackground());
767 else
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))
781 nInfo |= COLSELECT;
782 if ((GetSelection() != nullptr && GetSelectRowCount()) ||
783 (aMouseEvent.Is() && aMouseEvent->GetColumnId() == HandleColumnId))
784 nInfo |= ROWSELECT;
785 if (!nInfo && nNewRow != nEditRow)
786 nInfo |= ROWCHANGE;
787 if (!nInfo && nNewColId != nEditCol)
788 nInfo |= COLCHANGE;
790 if (nInfo == 0) // nothing happened
791 return true;
793 // save the cell content
794 if (IsEditing() && aController->IsValueChangedFromSaved() && !const_cast<EditBrowseBox *>(this)->SaveModified())
796 // maybe we're not visible ...
797 EnableAndShow();
798 aController->GetWindow().GrabFocus();
799 return false;
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)) &&
808 !pTHIS->SaveRow())
810 if (nInfo & COLSELECT ||
811 nInfo & ROWSELECT)
813 // cancel selected
814 pTHIS->SetNoSelection();
817 if (IsEditing())
819 if (!Controller()->GetWindow().IsVisible())
821 EnableAndShow();
823 aController->GetWindow().GrabFocus();
825 return false;
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);
848 return false;
850 else
852 rWindow.EnablePaint(true);
853 return true;
856 else
857 return pTHIS->CursorMoving(nNewRow, nNewColId);
861 void EditBrowseBox::ColumnMoved(sal_uInt16 nId)
863 BrowseBox::ColumnMoved(nId);
864 if (IsEditing())
866 tools::Rectangle aRect( GetCellRect(nEditRow, nEditCol, false));
867 CellControllerRef aControllerRef = Controller();
868 ResizeController(aControllerRef, aRect);
869 Controller()->GetWindow().GrabFocus();
874 bool EditBrowseBox::SaveRow()
876 return true;
880 bool EditBrowseBox::CursorMoving(sal_Int32, sal_uInt16)
882 DeactivateCell(false);
883 return true;
887 void EditBrowseBox::CursorMoved()
889 sal_Int32 nNewRow = GetCurRow();
890 if (nEditRow != nNewRow)
892 if (!(GetBrowserFlags() & EditBrowseBoxFlags::NO_HANDLE_COLUMN_CONTENT))
893 InvalidateStatusCell(nNewRow);
894 nEditRow = nNewRow;
896 ActivateCell();
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()
905 if (IsEditing())
907 tools::Rectangle aRect = GetCellRect(nEditRow, nEditCol, false);
908 ResizeController(aController,aRect);
909 AsynchGetFocus();
911 BrowseBox::EndScroll();
915 void EditBrowseBox::ActivateCell(sal_Int32 nRow, sal_uInt16 nCol, bool bCellFocus)
917 if (IsEditing())
918 return;
920 nEditCol = nCol;
922 if ((GetSelectRowCount() && GetSelection() != nullptr) || GetSelectColumnCount() ||
923 (aMouseEvent.Is() && (aMouseEvent.IsDown() || aMouseEvent->GetClicks() > 1))) // nothing happens on MouseDown
925 return;
928 if (nEditRow < 0 || nEditCol <= HandleColumnId)
929 return;
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));
941 EnableAndShow();
943 if ( isAccessibleAlive() )
944 implCreateActiveAccessible();
946 // activate the cell only of the browser has the focus
947 if ( bHasFocus && bCellFocus )
948 AsynchGetFocus();
950 else
952 // no controller -> we have a new "active descendant"
953 if ( isAccessibleAlive() && HasFocus() )
955 commitTableEvent(
956 ACTIVE_DESCENDANT_CHANGED,
957 Any( CreateAccessibleCell( nRow, GetColumnPos( nCol -1) ) ),
958 Any()
965 void EditBrowseBox::DeactivateCell(bool bUpdate)
967 if (!IsEditing())
968 return;
970 if ( isAccessibleAlive() )
972 commitBrowseBoxEvent( CHILD, Any(), Any( m_aImpl->m_xActiveCell ) );
973 m_aImpl->clearActiveCell();
976 aOldController = aController;
977 aController.clear();
979 // reset the modify handler
980 aOldController->SetModifyHdl(Link<LinkParamNone*,void>());
982 if (bHasFocus)
983 GrabFocus(); // ensure that we have (and keep) the focus
985 aOldController->suspend();
987 // update if requested
988 if (bUpdate)
989 PaintImmediately();
991 // release the controller (asynchronously)
992 if (nEndEvent)
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 );
1006 return aRect;
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;
1029 CellModified();
1032 void EditBrowseBox::ColumnResized( sal_uInt16 )
1034 if (IsEditing())
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())
1042 return;
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--)
1055 if (!nId)
1057 // if there is no handle column
1058 // increment the id
1059 if ( ColCount() == 0 || GetColumnId(0) != HandleColumnId )
1060 nId = ColCount() + 1;
1064 DBG_ASSERT(nId, "EditBrowseBox::AppendColumn: invalid id!");
1066 tools::Long w = nWidth;
1067 if (!w)
1068 w = GetDefaultColumnWidth(rName);
1070 InsertDataColumn(nId, rName, w, (HeaderBarItemBits::CENTER | HeaderBarItemBits::CLICKABLE), nPos);
1071 return nId;
1074 void EditBrowseBox::Resize()
1076 BrowseBox::Resize();
1078 // if the window is smaller than "title line height" + "control area",
1079 // do nothing
1080 if (GetOutputSizePixel().Height() <
1081 (GetControlArea().GetHeight() + GetDataWindow().GetPosPixel().Y()))
1082 return;
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()));
1090 if (!nX)
1091 nX = USHRT_MAX;
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
1097 if (bChanged)
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)
1110 return nullptr;
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()
1140 return true;
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));
1169 else
1170 nNewColWidth = GetDefaultColumnWidth(GetColumnTitle(nColId));
1171 return nNewColWidth;
1174 sal_uInt32 EditBrowseBox::GetTotalCellWidth(sal_Int32, sal_uInt16)
1176 return 0;
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)),
1196 aBoxSize);
1197 pCheckBoxPaint->SetPosSizePixel(aRect.TopLeft(), aRect.GetSize());
1199 pCheckBoxPaint->Draw(GetDataWindow().GetOutDev(), aRect.TopLeft(), SystemTextColorFlags::NONE);
1202 void EditBrowseBox::AsynchGetFocus()
1204 if (nStartEvent)
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)
1215 return;
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)
1231 : pWindow(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( );
1251 bSuspended = true;
1255 void CellController::resume( )
1257 DBG_ASSERT( bSuspended == !GetWindow().IsVisible(), "CellController::resume: inconsistence!" );
1258 if ( isSuspended( ) )
1260 GetWindow().Enable( );
1261 GetWindow().Show( );
1262 bSuspended = false;
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
1278 return true;
1281 } // namespace svt
1284 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */