summaryrefslogtreecommitdiffstats
path: root/svtools/source/brwbox/editbrowsebox.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'svtools/source/brwbox/editbrowsebox.cxx')
-rw-r--r--svtools/source/brwbox/editbrowsebox.cxx1284
1 files changed, 1284 insertions, 0 deletions
diff --git a/svtools/source/brwbox/editbrowsebox.cxx b/svtools/source/brwbox/editbrowsebox.cxx
new file mode 100644
index 000000000..8cadf4748
--- /dev/null
+++ b/svtools/source/brwbox/editbrowsebox.cxx
@@ -0,0 +1,1284 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svtools/editbrowsebox.hxx>
+
+#include <tools/debug.hxx>
+#include <vcl/image.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/window.hxx>
+#include <vcl/svapp.hxx>
+
+#include <bitmaps.hlst>
+
+#include <algorithm>
+#include "editbrowseboximpl.hxx"
+#include <com/sun/star/accessibility/AccessibleEventId.hpp>
+
+
+namespace svt
+{
+
+ namespace
+ {
+
+ GetFocusFlags getRealGetFocusFlags( vcl::Window* _pWindow )
+ {
+ GetFocusFlags nFlags = GetFocusFlags::NONE;
+ while ( _pWindow && nFlags == GetFocusFlags::NONE )
+ {
+ nFlags = _pWindow->GetGetFocusFlags( );
+ _pWindow = _pWindow->GetParent();
+ }
+ return nFlags;
+ }
+ }
+
+ using namespace ::com::sun::star::uno;
+ using namespace com::sun::star::accessibility::AccessibleEventId;
+
+
+ IEditImplementation::~IEditImplementation()
+ {
+ }
+
+ //= EditBrowserHeader
+
+ void EditBrowserHeader::DoubleClick()
+ {
+ sal_uInt16 nColId = GetCurItemId();
+ if (nColId)
+ {
+ sal_uInt32 nAutoWidth = static_cast<EditBrowseBox*>(GetParent())->GetAutoColumnWidth(nColId);
+ if (nAutoWidth != static_cast<EditBrowseBox*>(GetParent())->GetColumnWidth(nColId))
+ {
+ static_cast<EditBrowseBox*>(GetParent())->SetColumnWidth(nColId, nAutoWidth);
+ static_cast<EditBrowseBox*>(GetParent())->ColumnResized(nColId);
+ }
+ }
+ }
+
+ //= EditBrowseBox
+
+ void EditBrowseBox::BrowserMouseEventPtr::Clear()
+ {
+ pEvent.reset();
+ }
+
+ void EditBrowseBox::BrowserMouseEventPtr::Set(const BrowserMouseEvent* pEvt, bool bIsDown)
+ {
+ if (pEvt == pEvent.get())
+ {
+ bDown = bIsDown;
+ return;
+ }
+ pEvent.reset();
+ if (pEvt)
+ {
+ pEvent.reset(new BrowserMouseEvent(pEvt->GetWindow(),
+ *pEvt,
+ pEvt->GetRow(),
+ pEvt->GetColumn(),
+ pEvt->GetColumnId(),
+ pEvt->GetRect()));
+ bDown = bIsDown;
+ }
+ }
+
+ EditBrowseBox::EditBrowseBox( vcl::Window* pParent, EditBrowseBoxFlags nBrowserFlags, WinBits nBits, BrowserMode _nMode )
+ :BrowseBox( pParent, nBits, _nMode )
+ ,nStartEvent(nullptr)
+ ,nEndEvent(nullptr)
+ ,nCellModifiedEvent(nullptr)
+ ,m_pFocusWhileRequest(nullptr)
+ ,nPaintRow(-1)
+ ,nEditRow(-1)
+ ,nEditCol(0)
+ ,bHasFocus(false)
+ ,bPaintStatus(true)
+ ,bActiveBeforeTracking( false )
+ ,m_nBrowserFlags(nBrowserFlags)
+ ,pHeader(nullptr)
+ {
+ m_aImpl.reset(new EditBrowseBoxImpl);
+
+ SetCompoundControl(true);
+
+ ImplInitSettings(true, true, true);
+
+ pCheckBoxPaint = VclPtr<CheckBoxControl>::Create(&GetDataWindow());
+ pCheckBoxPaint->SetPaintTransparent( true );
+ pCheckBoxPaint->SetBackground();
+ }
+
+ void EditBrowseBox::Init()
+ {
+ // late construction
+ }
+
+ EditBrowseBox::~EditBrowseBox()
+ {
+ disposeOnce();
+ }
+
+ void EditBrowseBox::dispose()
+ {
+ if (nStartEvent)
+ Application::RemoveUserEvent(nStartEvent);
+ if (nEndEvent)
+ Application::RemoveUserEvent(nEndEvent);
+ if (nCellModifiedEvent)
+ Application::RemoveUserEvent(nCellModifiedEvent);
+
+ pCheckBoxPaint.disposeAndClear();
+ m_pFocusWhileRequest.clear();
+ pHeader.clear();
+ BrowseBox::dispose();
+ }
+
+
+ void EditBrowseBox::RemoveRows()
+ {
+ BrowseBox::Clear();
+ nEditRow = nPaintRow = -1;
+ nEditCol = 0;
+ }
+
+ VclPtr<BrowserHeader> EditBrowseBox::CreateHeaderBar(BrowseBox* pParent)
+ {
+ pHeader = imp_CreateHeaderBar(pParent);
+ if (!IsUpdateMode())
+ pHeader->SetUpdateMode(false);
+ return pHeader;
+ }
+
+ VclPtr<BrowserHeader> EditBrowseBox::imp_CreateHeaderBar(BrowseBox* pParent)
+ {
+ return VclPtr<EditBrowserHeader>::Create(pParent);
+ }
+
+ void EditBrowseBox::LoseFocus()
+ {
+ BrowseBox::LoseFocus();
+ DetermineFocus();
+ }
+
+ void EditBrowseBox::GetFocus()
+ {
+ BrowseBox::GetFocus();
+
+ // This should handle the case that the BrowseBox (or one of its children)
+ // gets the focus from outside by pressing Tab
+ if (IsEditing() && Controller()->GetWindow().IsVisible())
+ Controller()->GetWindow().GrabFocus();
+
+ DetermineFocus(getRealGetFocusFlags(this));
+ }
+
+ bool EditBrowseBox::SeekRow(sal_Int32 nRow)
+ {
+ nPaintRow = nRow;
+ return true;
+ }
+
+ IMPL_LINK_NOARG(EditBrowseBox, StartEditHdl, void*, void)
+ {
+ nStartEvent = nullptr;
+ if (IsEditing())
+ {
+ EnableAndShow();
+ if (!ControlHasFocus() && (m_pFocusWhileRequest.get() == Application::GetFocusWindow()))
+ aController->GetWindow().GrabFocus();
+ }
+ }
+
+ void EditBrowseBox::PaintField( vcl::RenderContext& rDev, const tools::Rectangle& rRect,
+ sal_uInt16 nColumnId ) const
+ {
+ if (nColumnId == HandleColumnId)
+ {
+ if (bPaintStatus)
+ PaintStatusCell(rDev, rRect);
+ }
+ else
+ {
+ // don't paint the current cell
+ if (rDev.GetOwnerWindow() == &GetDataWindow())
+ // but only if we're painting onto our data win (which is the usual painting)
+ if (nPaintRow == nEditRow)
+ {
+ if (IsEditing() && nEditCol == nColumnId && aController->GetWindow().IsVisible())
+ return;
+ }
+ PaintCell(rDev, rRect, nColumnId);
+ }
+ }
+
+ Image EditBrowseBox::GetImage(RowStatus eStatus) const
+ {
+ BitmapEx aBitmap;
+ bool bNeedMirror = IsRTLEnabled();
+ switch (eStatus)
+ {
+ case CURRENT:
+ aBitmap = BitmapEx(BMP_CURRENT);
+ break;
+ case CURRENTNEW:
+ aBitmap = BitmapEx(BMP_CURRENTNEW);
+ break;
+ case MODIFIED:
+ aBitmap = BitmapEx(BMP_MODIFIED);
+ bNeedMirror = false; // the pen is not mirrored
+ break;
+ case NEW:
+ aBitmap = BitmapEx(BMP_NEW);
+ break;
+ case DELETED:
+ aBitmap = BitmapEx(BMP_DELETED);
+ break;
+ case PRIMARYKEY:
+ aBitmap = BitmapEx(BMP_PRIMARYKEY);
+ break;
+ case CURRENT_PRIMARYKEY:
+ aBitmap = BitmapEx(BMP_CURRENT_PRIMARYKEY);
+ break;
+ case FILTER:
+ aBitmap = BitmapEx(BMP_FILTER);
+ break;
+ case HEADERFOOTER:
+ aBitmap = BitmapEx(BMP_HEADERFOOTER);
+ break;
+ case CLEAN:
+ break;
+ }
+ if ( bNeedMirror )
+ {
+ aBitmap.Mirror( BmpMirrorFlags::Horizontal );
+ }
+ return Image(aBitmap);
+ }
+
+ void EditBrowseBox::PaintStatusCell(OutputDevice& rDev, const tools::Rectangle& rRect) const
+ {
+ if (nPaintRow < 0)
+ return;
+
+ RowStatus eStatus = GetRowStatus( nPaintRow );
+ EditBrowseBoxFlags nBrowserFlags = GetBrowserFlags();
+
+ if (nBrowserFlags & EditBrowseBoxFlags::NO_HANDLE_COLUMN_CONTENT)
+ return;
+
+ // draw the text of the header column
+ if (nBrowserFlags & EditBrowseBoxFlags::HANDLE_COLUMN_TEXT )
+ {
+ rDev.DrawText( rRect, GetCellText( nPaintRow, 0 ),
+ DrawTextFlags::Center | DrawTextFlags::VCenter | DrawTextFlags::Clip );
+ }
+ // draw an image
+ else if (eStatus != CLEAN && rDev.GetOutDevType() == OUTDEV_WINDOW)
+ {
+ Image aImage(GetImage(eStatus));
+ // calc the image position
+ Size aImageSize(aImage.GetSizePixel());
+ aImageSize.setWidth( CalcZoom(aImageSize.Width()) );
+ aImageSize.setHeight( CalcZoom(aImageSize.Height()) );
+ Point aPos( rRect.TopLeft() );
+
+ if ( ( aImageSize.Width() > rRect.GetWidth() ) || ( aImageSize.Height() > rRect.GetHeight() ) )
+ rDev.SetClipRegion(vcl::Region(rRect));
+
+ if ( aImageSize.Width() < rRect.GetWidth() )
+ aPos.AdjustX(( rRect.GetWidth() - aImageSize.Width() ) / 2 );
+
+ if ( aImageSize.Height() < rRect.GetHeight() )
+ aPos.AdjustY(( rRect.GetHeight() - aImageSize.Height() ) / 2 );
+
+ if ( IsZoom() )
+ rDev.DrawImage( aPos, aImageSize, aImage );
+ else
+ rDev.DrawImage( aPos, aImage );
+
+ if (rDev.IsClipRegion())
+ rDev.SetClipRegion();
+ }
+ }
+
+
+ void EditBrowseBox::ImplStartTracking()
+ {
+ bActiveBeforeTracking = IsEditing();
+ if ( bActiveBeforeTracking )
+ {
+ DeactivateCell();
+ PaintImmediately();
+ }
+
+ BrowseBox::ImplStartTracking();
+ }
+
+
+ void EditBrowseBox::ImplEndTracking()
+ {
+ if ( bActiveBeforeTracking )
+ ActivateCell();
+ bActiveBeforeTracking = false;
+
+ BrowseBox::ImplEndTracking();
+ }
+
+
+ void EditBrowseBox::RowHeightChanged()
+ {
+ if ( IsEditing() )
+ {
+ tools::Rectangle aRect( GetCellRect( nEditRow, nEditCol, false ) );
+ CellControllerRef aCellController( Controller() );
+ ResizeController( aCellController, aRect );
+ aCellController->GetWindow().GrabFocus();
+ }
+
+ BrowseBox::RowHeightChanged();
+ }
+
+
+ EditBrowseBox::RowStatus EditBrowseBox::GetRowStatus(sal_Int32) const
+ {
+ return CLEAN;
+ }
+
+
+ void EditBrowseBox::KeyInput( const KeyEvent& rEvt )
+ {
+ sal_uInt16 nCode = rEvt.GetKeyCode().GetCode();
+ bool bShift = rEvt.GetKeyCode().IsShift();
+ bool bCtrl = rEvt.GetKeyCode().IsMod1();
+
+ switch (nCode)
+ {
+ case KEY_RETURN:
+ if (!bCtrl && !bShift && IsTabAllowed(true))
+ {
+ Dispatch(BROWSER_CURSORRIGHT);
+ }
+ else
+ BrowseBox::KeyInput(rEvt);
+ return;
+ case KEY_TAB:
+ if (!bCtrl && !bShift)
+ {
+ if (IsTabAllowed(true))
+ Dispatch(BROWSER_CURSORRIGHT);
+ else
+ // do NOT call BrowseBox::KeyInput : this would handle the tab, but we already now
+ // that tab isn't allowed here. So give the Control class a chance
+ Control::KeyInput(rEvt);
+ return;
+ }
+ else if (!bCtrl && bShift)
+ {
+ if (IsTabAllowed(false))
+ Dispatch(BROWSER_CURSORLEFT);
+ else
+ // do NOT call BrowseBox::KeyInput : this would handle the tab, but we already now
+ // that tab isn't allowed here. So give the Control class a chance
+ Control::KeyInput(rEvt);
+ return;
+ }
+ [[fallthrough]];
+ default:
+ BrowseBox::KeyInput(rEvt);
+ }
+ }
+
+ void EditBrowseBox::ChildFocusIn()
+ {
+ DetermineFocus(getRealGetFocusFlags(this));
+ }
+
+ void EditBrowseBox::ChildFocusOut()
+ {
+ DetermineFocus();
+ }
+
+ void EditBrowseBox::MouseButtonDown(const BrowserMouseEvent& rEvt)
+ {
+ // absorb double clicks
+ if (rEvt.GetClicks() > 1 && rEvt.GetRow() >= 0)
+ return;
+
+ // we are about to leave the current cell. If there is a "this cell has been modified" notification
+ // pending (asynchronously), this may be deadly -> do it synchronously
+ if ( nCellModifiedEvent )
+ {
+ Application::RemoveUserEvent( nCellModifiedEvent );
+ nCellModifiedEvent = nullptr;
+ LINK( this, EditBrowseBox, CellModifiedHdl ).Call( nullptr );
+ }
+
+ if (rEvt.GetColumnId() == HandleColumnId)
+ { // it was the handle column. save the current cell content if necessary
+ // (clicking on the handle column results in selecting the current row)
+ if (IsEditing() && aController->IsValueChangedFromSaved())
+ SaveModified();
+ }
+
+ aMouseEvent.Set(&rEvt,true);
+ BrowseBox::MouseButtonDown(rEvt);
+ aMouseEvent.Clear();
+
+ if (m_nBrowserFlags & EditBrowseBoxFlags::ACTIVATE_ON_BUTTONDOWN)
+ {
+ // the base class does not travel upon MouseButtonDown, but implActivateCellOnMouseEvent assumes we traveled ...
+ GoToRowColumnId( rEvt.GetRow(), rEvt.GetColumnId() );
+ if (rEvt.GetRow() >= 0)
+ implActivateCellOnMouseEvent(rEvt, false);
+ }
+ }
+
+ void EditBrowseBox::MouseButtonUp( const BrowserMouseEvent& rEvt )
+ {
+ // absorb double clicks
+ if (rEvt.GetClicks() > 1 && rEvt.GetRow() >= 0)
+ return;
+
+ aMouseEvent.Set(&rEvt,false);
+ BrowseBox::MouseButtonUp(rEvt);
+ aMouseEvent.Clear();
+
+ if (!(m_nBrowserFlags & EditBrowseBoxFlags::ACTIVATE_ON_BUTTONDOWN))
+ if (rEvt.GetRow() >= 0)
+ implActivateCellOnMouseEvent(rEvt, true);
+ }
+
+ bool EditBrowseBox::ControlHasFocus() const
+ {
+ Window* pControlWindow = aController ? &aController->GetWindow() : nullptr;
+ if (ControlBase* pControlBase = dynamic_cast<ControlBase*>(pControlWindow))
+ return pControlBase->ControlHasFocus();
+ return pControlWindow && pControlWindow->HasChildPathFocus();
+ }
+
+ void EditBrowseBox::implActivateCellOnMouseEvent(const BrowserMouseEvent& _rEvt, bool _bUp)
+ {
+ if (!IsEditing())
+ ActivateCell();
+ else if (IsEditing() && !aController->GetWindow().IsEnabled())
+ DeactivateCell();
+ else if (IsEditing() && !ControlHasFocus())
+ AsynchGetFocus();
+
+ if (!IsEditing() || !aController->GetWindow().IsEnabled())
+ return;
+
+ // forwards the event to the control
+ aController->ActivatingMouseEvent(_rEvt, _bUp);
+ }
+
+ void EditBrowseBox::Dispatch( sal_uInt16 _nId )
+ {
+ if ( _nId == BROWSER_ENHANCESELECTION )
+ { // this is a workaround for the bug in the base class:
+ // if the row selection is to be extended (which is what BROWSER_ENHANCESELECTION tells us)
+ // then the base class does not revert any column selections, while, for doing a "simple"
+ // selection (BROWSER_SELECT), it does. In fact, it does not only revert the col selection then,
+ // but also any current row selections.
+ // This clearly tells me that the both ids are for row selection only - there this behaviour does
+ // make sense.
+ // But here, where we have column selection, too, we take care of this ourself.
+ if ( GetSelectColumnCount( ) )
+ {
+ while ( GetSelectColumnCount( ) )
+ SelectColumnPos(
+ sal::static_int_cast< sal_uInt16 >(FirstSelectedColumn()),
+ false );
+ Select();
+ }
+ }
+ BrowseBox::Dispatch( _nId );
+ }
+
+ bool EditBrowseBox::ProcessKey(const KeyEvent& rKeyEvent)
+ {
+ sal_uInt16 nCode = rKeyEvent.GetKeyCode().GetCode();
+ bool bShift = rKeyEvent.GetKeyCode().IsShift();
+ bool bCtrl = rKeyEvent.GetKeyCode().IsMod1();
+ bool bAlt = rKeyEvent.GetKeyCode().IsMod2();
+ bool bLocalSelect = false;
+ bool bNonEditOnly = false;
+ sal_uInt16 nId = BROWSER_NONE;
+
+ if (!bAlt && !bCtrl && !bShift )
+ switch ( nCode )
+ {
+ case KEY_DOWN: nId = BROWSER_CURSORDOWN; break;
+ case KEY_UP: nId = BROWSER_CURSORUP; break;
+ case KEY_PAGEDOWN: nId = BROWSER_CURSORPAGEDOWN; break;
+ case KEY_PAGEUP: nId = BROWSER_CURSORPAGEUP; break;
+ case KEY_HOME: nId = BROWSER_CURSORHOME; break;
+ case KEY_END: nId = BROWSER_CURSOREND; break;
+
+ case KEY_TAB:
+ // ask if traveling to the next cell is allowed
+ if (IsTabAllowed(true))
+ nId = BROWSER_CURSORRIGHT;
+ break;
+
+ case KEY_RETURN:
+ // save the cell content (if necessary)
+ if (IsEditing() && aController->IsValueChangedFromSaved() && !SaveModified())
+ {
+ // maybe we're not visible ...
+ EnableAndShow();
+ aController->GetWindow().GrabFocus();
+ return true;
+ }
+ // ask if traveling to the next cell is allowed
+ if (IsTabAllowed(true))
+ nId = BROWSER_CURSORRIGHT;
+
+ break;
+ case KEY_RIGHT: nId = BROWSER_CURSORRIGHT; break;
+ case KEY_LEFT: nId = BROWSER_CURSORLEFT; break;
+ case KEY_SPACE: nId = BROWSER_SELECT; bNonEditOnly = bLocalSelect = true; break;
+ }
+
+ if ( !bAlt && !bCtrl && bShift )
+ switch ( nCode )
+ {
+ case KEY_DOWN: nId = BROWSER_SELECTDOWN; bLocalSelect = true; break;
+ case KEY_UP: nId = BROWSER_SELECTUP; bLocalSelect = true; break;
+ case KEY_HOME: nId = BROWSER_SELECTHOME; bLocalSelect = true; break;
+ case KEY_END: nId = BROWSER_SELECTEND; bLocalSelect = true; break;
+ case KEY_TAB:
+ if (IsTabAllowed(false))
+ nId = BROWSER_CURSORLEFT;
+ break;
+ }
+
+ if ( !bAlt && bCtrl && bShift )
+ switch ( nCode )
+ {
+ case KEY_SPACE: nId = BROWSER_SELECTCOLUMN; bLocalSelect = true; break;
+ }
+
+
+ if ( !bAlt && bCtrl && !bShift )
+ switch ( nCode )
+ {
+ case KEY_DOWN: nId = BROWSER_SCROLLUP; break;
+ case KEY_UP: nId = BROWSER_SCROLLDOWN; break;
+ case KEY_PAGEDOWN: nId = BROWSER_CURSORENDOFFILE; break;
+ case KEY_PAGEUP: nId = BROWSER_CURSORTOPOFFILE; break;
+ case KEY_HOME: nId = BROWSER_CURSORTOPOFSCREEN; break;
+ case KEY_END: nId = BROWSER_CURSORENDOFSCREEN; break;
+ case KEY_SPACE: nId = BROWSER_ENHANCESELECTION; bLocalSelect = true; break;
+ }
+
+
+ if ( ( nId != BROWSER_NONE )
+ && ( !IsEditing()
+ || ( !bNonEditOnly
+ && aController->MoveAllowed(rKeyEvent)
+ )
+ )
+ )
+ {
+ if (nId == BROWSER_SELECT || BROWSER_SELECTCOLUMN == nId )
+ {
+ // save the cell content (if necessary)
+ if (IsEditing() && aController->IsValueChangedFromSaved() && !SaveModified())
+ {
+ // maybe we're not visible ...
+ EnableAndShow();
+ aController->GetWindow().GrabFocus();
+ return true;
+ }
+ }
+
+ Dispatch(nId);
+
+ if (bLocalSelect && (GetSelectRowCount() || GetSelection() != nullptr))
+ DeactivateCell();
+ return true;
+ }
+ return false;
+ }
+
+ bool EditBrowseBox::PreNotify(NotifyEvent& rEvt)
+ {
+ if (rEvt.GetType() == MouseNotifyEvent::KEYINPUT)
+ {
+ if ( (IsEditing() && ControlHasFocus())
+ || rEvt.GetWindow() == &GetDataWindow()
+ || (!IsEditing() && HasChildPathFocus())
+ )
+ {
+ if (ProcessKey(*rEvt.GetKeyEvent()))
+ return true;
+ }
+ }
+ return BrowseBox::PreNotify(rEvt);
+ }
+
+ bool EditBrowseBox::IsTabAllowed(bool) const
+ {
+ return true;
+ }
+
+
+ bool EditBrowseBox::EventNotify(NotifyEvent& rEvt)
+ {
+ switch (rEvt.GetType())
+ {
+ case MouseNotifyEvent::GETFOCUS:
+ DetermineFocus(getRealGetFocusFlags(this));
+ break;
+
+ case MouseNotifyEvent::LOSEFOCUS:
+ DetermineFocus();
+ break;
+
+ default:
+ break;
+ }
+ return BrowseBox::EventNotify(rEvt);
+ }
+
+
+ void EditBrowseBox::StateChanged( StateChangedType nType )
+ {
+ BrowseBox::StateChanged( nType );
+
+ bool bNeedCellReActivation = false;
+ if ( nType == StateChangedType::Mirroring )
+ {
+ bNeedCellReActivation = true;
+ }
+ else if ( nType == StateChangedType::Zoom )
+ {
+ ImplInitSettings( true, false, false );
+ bNeedCellReActivation = true;
+ }
+ else if ( nType == StateChangedType::ControlFont )
+ {
+ ImplInitSettings( true, false, false );
+ Invalidate();
+ }
+ else if ( nType == StateChangedType::ControlForeground )
+ {
+ ImplInitSettings( false, true, false );
+ Invalidate();
+ }
+ else if ( nType == StateChangedType::ControlBackground )
+ {
+ ImplInitSettings( false, false, true );
+ Invalidate();
+ }
+ else if (nType == StateChangedType::Style)
+ {
+ WinBits nStyle = GetStyle();
+ if (!(nStyle & WB_NOTABSTOP) )
+ nStyle |= WB_TABSTOP;
+
+ SetStyle(nStyle);
+ }
+ if ( bNeedCellReActivation )
+ {
+ if ( IsEditing() )
+ {
+ DeactivateCell();
+ ActivateCell();
+ }
+ }
+ }
+
+
+ void EditBrowseBox::DataChanged( const DataChangedEvent& rDCEvt )
+ {
+ BrowseBox::DataChanged( rDCEvt );
+
+ if ((( rDCEvt.GetType() == DataChangedEventType::SETTINGS ) ||
+ ( rDCEvt.GetType() == DataChangedEventType::DISPLAY )) &&
+ ( rDCEvt.GetFlags() & AllSettingsFlags::STYLE ))
+ {
+ ImplInitSettings( true, true, true );
+ Invalidate();
+ }
+ }
+
+ void EditBrowseBox::ImplInitSettings( bool bFont, bool bForeground, bool bBackground )
+ {
+ const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
+
+ if (bFont)
+ {
+ vcl::Font aFont = rStyleSettings.GetFieldFont();
+ if (IsControlFont())
+ {
+ GetDataWindow().SetControlFont(GetControlFont());
+ aFont.Merge(GetControlFont());
+ }
+ else
+ GetDataWindow().SetControlFont();
+
+ GetDataWindow().SetZoomedPointFont(*GetDataWindow().GetOutDev(), aFont);
+ }
+
+ if (bFont || bForeground)
+ {
+ Color aTextColor = rStyleSettings.GetFieldTextColor();
+ if (IsControlForeground())
+ {
+ aTextColor = GetControlForeground();
+ GetDataWindow().SetControlForeground(aTextColor);
+ }
+ else
+ GetDataWindow().SetControlForeground();
+
+ GetDataWindow().SetTextColor( aTextColor );
+ }
+
+ if (!bBackground) // FIXME: Outside of Paint Hierarchy
+ return;
+
+ if (GetDataWindow().IsControlBackground())
+ {
+ GetDataWindow().SetControlBackground(GetControlBackground());
+ GetDataWindow().SetBackground(GetDataWindow().GetControlBackground());
+ GetDataWindow().GetOutDev()->SetFillColor(GetDataWindow().GetControlBackground());
+ }
+ else
+ {
+ GetDataWindow().SetControlBackground();
+ GetDataWindow().SetBackground(rStyleSettings.GetFieldColor());
+ GetDataWindow().GetOutDev()->SetFillColor(rStyleSettings.GetFieldColor());
+ }
+ }
+
+
+ bool EditBrowseBox::IsCursorMoveAllowed(sal_Int32 nNewRow, sal_uInt16 nNewColId) const
+ {
+ sal_uInt16 nInfo = 0;
+
+ if (GetSelectColumnCount() || (aMouseEvent.Is() && aMouseEvent->GetRow() < 0))
+ nInfo |= COLSELECT;
+ if ((GetSelection() != nullptr && GetSelectRowCount()) ||
+ (aMouseEvent.Is() && aMouseEvent->GetColumnId() == HandleColumnId))
+ nInfo |= ROWSELECT;
+ if (!nInfo && nNewRow != nEditRow)
+ nInfo |= ROWCHANGE;
+ if (!nInfo && nNewColId != nEditCol)
+ nInfo |= COLCHANGE;
+
+ if (nInfo == 0) // nothing happened
+ return true;
+
+ // save the cell content
+ if (IsEditing() && aController->IsValueChangedFromSaved() && !const_cast<EditBrowseBox *>(this)->SaveModified())
+ {
+ // maybe we're not visible ...
+ EnableAndShow();
+ aController->GetWindow().GrabFocus();
+ return false;
+ }
+
+ EditBrowseBox * pTHIS = const_cast<EditBrowseBox *> (this);
+
+ // save the cell content if
+ // a) a selection is being made
+ // b) the row is changing
+ if (IsModified() && (nInfo & (ROWCHANGE | COLSELECT | ROWSELECT)) &&
+ !pTHIS->SaveRow())
+ {
+ if (nInfo & COLSELECT ||
+ nInfo & ROWSELECT)
+ {
+ // cancel selected
+ pTHIS->SetNoSelection();
+ }
+
+ if (IsEditing())
+ {
+ if (!Controller()->GetWindow().IsVisible())
+ {
+ EnableAndShow();
+ }
+ aController->GetWindow().GrabFocus();
+ }
+ return false;
+ }
+
+ if (nNewRow != nEditRow)
+ {
+ vcl::Window& rWindow = GetDataWindow();
+ if ((nEditRow >= 0) && !(GetBrowserFlags() & EditBrowseBoxFlags::NO_HANDLE_COLUMN_CONTENT))
+ {
+ tools::Rectangle aRect = GetFieldRectPixel(nEditRow, 0, false );
+ // status cell should be painted if and only if text is displayed
+ pTHIS->bPaintStatus = ( GetBrowserFlags() & EditBrowseBoxFlags::HANDLE_COLUMN_TEXT ) == EditBrowseBoxFlags::HANDLE_COLUMN_TEXT;
+ rWindow.Invalidate(aRect);
+ pTHIS->bPaintStatus = true;
+ }
+
+ // don't paint during row change
+ rWindow.EnablePaint(false);
+
+ // the last veto chance for derived classes
+ if (!pTHIS->CursorMoving(nNewRow, nNewColId))
+ {
+ pTHIS->InvalidateStatusCell(nEditRow);
+ rWindow.EnablePaint(true);
+ return false;
+ }
+ else
+ {
+ rWindow.EnablePaint(true);
+ return true;
+ }
+ }
+ else
+ return pTHIS->CursorMoving(nNewRow, nNewColId);
+ }
+
+
+ void EditBrowseBox::ColumnMoved(sal_uInt16 nId)
+ {
+ BrowseBox::ColumnMoved(nId);
+ if (IsEditing())
+ {
+ tools::Rectangle aRect( GetCellRect(nEditRow, nEditCol, false));
+ CellControllerRef aControllerRef = Controller();
+ ResizeController(aControllerRef, aRect);
+ Controller()->GetWindow().GrabFocus();
+ }
+ }
+
+
+ bool EditBrowseBox::SaveRow()
+ {
+ return true;
+ }
+
+
+ bool EditBrowseBox::CursorMoving(sal_Int32, sal_uInt16)
+ {
+ DeactivateCell(false);
+ return true;
+ }
+
+
+ void EditBrowseBox::CursorMoved()
+ {
+ sal_Int32 nNewRow = GetCurRow();
+ if (nEditRow != nNewRow)
+ {
+ if (!(GetBrowserFlags() & EditBrowseBoxFlags::NO_HANDLE_COLUMN_CONTENT))
+ InvalidateStatusCell(nNewRow);
+ nEditRow = nNewRow;
+ }
+ ActivateCell();
+ GetDataWindow().EnablePaint(true);
+ // should not be called here because the descant event is not needed here
+ //BrowseBox::CursorMoved();
+ }
+
+
+ void EditBrowseBox::EndScroll()
+ {
+ if (IsEditing())
+ {
+ tools::Rectangle aRect = GetCellRect(nEditRow, nEditCol, false);
+ ResizeController(aController,aRect);
+ AsynchGetFocus();
+ }
+ BrowseBox::EndScroll();
+ }
+
+
+ void EditBrowseBox::ActivateCell(sal_Int32 nRow, sal_uInt16 nCol, bool bCellFocus)
+ {
+ if (IsEditing())
+ return;
+
+ nEditCol = nCol;
+
+ if ((GetSelectRowCount() && GetSelection() != nullptr) || GetSelectColumnCount() ||
+ (aMouseEvent.Is() && (aMouseEvent.IsDown() || aMouseEvent->GetClicks() > 1))) // nothing happens on MouseDown
+ {
+ return;
+ }
+
+ if (nEditRow < 0 || nEditCol <= HandleColumnId)
+ return;
+
+ aController = GetController(nRow, nCol);
+ if (aController.is())
+ {
+ tools::Rectangle aRect( GetCellRect(nEditRow, nEditCol, false));
+ ResizeController(aController, aRect);
+
+ InitController(aController, nEditRow, nEditCol);
+
+ aController->SaveValue();
+ aController->SetModifyHdl(LINK(this,EditBrowseBox,ModifyHdl));
+ EnableAndShow();
+
+ if ( isAccessibleAlive() )
+ implCreateActiveAccessible();
+
+ // activate the cell only of the browser has the focus
+ if ( bHasFocus && bCellFocus )
+ AsynchGetFocus();
+ }
+ else
+ {
+ // no controller -> we have a new "active descendant"
+ if ( isAccessibleAlive() && HasFocus() )
+ {
+ commitTableEvent(
+ ACTIVE_DESCENDANT_CHANGED,
+ Any( CreateAccessibleCell( nRow, GetColumnPos( nCol -1) ) ),
+ Any()
+ );
+ }
+ }
+ }
+
+
+ void EditBrowseBox::DeactivateCell(bool bUpdate)
+ {
+ if (!IsEditing())
+ return;
+
+ if ( isAccessibleAlive() )
+ {
+ commitBrowseBoxEvent( CHILD, Any(), Any( m_aImpl->m_xActiveCell ) );
+ m_aImpl->clearActiveCell();
+ }
+
+ aOldController = aController;
+ aController.clear();
+
+ // reset the modify handler
+ aOldController->SetModifyHdl(Link<LinkParamNone*,void>());
+
+ if (bHasFocus)
+ GrabFocus(); // ensure that we have (and keep) the focus
+
+ aOldController->suspend();
+
+ // update if requested
+ if (bUpdate)
+ PaintImmediately();
+
+ // release the controller (asynchronously)
+ if (nEndEvent)
+ Application::RemoveUserEvent(nEndEvent);
+ nEndEvent = Application::PostUserEvent(LINK(this,EditBrowseBox,EndEditHdl), nullptr, true);
+ }
+
+
+ tools::Rectangle EditBrowseBox::GetCellRect(sal_Int32 nRow, sal_uInt16 nColId, bool bRel) const
+ {
+ tools::Rectangle aRect( GetFieldRectPixel(nRow, nColId, bRel));
+ if ((GetMode() & BrowserMode::CURSOR_WO_FOCUS) == BrowserMode::CURSOR_WO_FOCUS)
+ {
+ aRect.AdjustTop(1 );
+ aRect.AdjustBottom( -1 );
+ }
+ return aRect;
+ }
+
+
+ IMPL_LINK_NOARG(EditBrowseBox, EndEditHdl, void*, void)
+ {
+ nEndEvent = nullptr;
+
+ aOldController = CellControllerRef();
+ }
+
+
+ IMPL_LINK_NOARG(EditBrowseBox, ModifyHdl, LinkParamNone*, void)
+ {
+ if (nCellModifiedEvent)
+ Application::RemoveUserEvent(nCellModifiedEvent);
+ nCellModifiedEvent = Application::PostUserEvent(LINK(this,EditBrowseBox,CellModifiedHdl), nullptr, true);
+ }
+
+
+ IMPL_LINK_NOARG(EditBrowseBox, CellModifiedHdl, void*, void)
+ {
+ nCellModifiedEvent = nullptr;
+ CellModified();
+ }
+
+ void EditBrowseBox::ColumnResized( sal_uInt16 )
+ {
+ if (IsEditing())
+ {
+ tools::Rectangle aRect( GetCellRect(nEditRow, nEditCol, false));
+ CellControllerRef aControllerRef = Controller();
+ ResizeController(aControllerRef, aRect);
+ // don't grab focus if Field Properties panel is being
+ // resized by split pane drag resizing
+ if (Application::IsUICaptured())
+ return;
+ Controller()->GetWindow().GrabFocus();
+ }
+ }
+
+ sal_uInt16 EditBrowseBox::AppendColumn(const OUString& rName, sal_uInt16 nWidth, sal_uInt16 nPos, sal_uInt16 nId)
+ {
+ if (nId == BROWSER_INVALIDID)
+ {
+ // look for the next free id
+ for (nId = ColCount(); nId > 0 && GetColumnPos(nId) != BROWSER_INVALIDID; nId--)
+ ;
+
+ if (!nId)
+ {
+ // if there is no handle column
+ // increment the id
+ if ( ColCount() == 0 || GetColumnId(0) != HandleColumnId )
+ nId = ColCount() + 1;
+ }
+ }
+
+ DBG_ASSERT(nId, "EditBrowseBox::AppendColumn: invalid id!");
+
+ tools::Long w = nWidth;
+ if (!w)
+ w = GetDefaultColumnWidth(rName);
+
+ InsertDataColumn(nId, rName, w, (HeaderBarItemBits::CENTER | HeaderBarItemBits::CLICKABLE), nPos);
+ return nId;
+ }
+
+ void EditBrowseBox::Resize()
+ {
+ BrowseBox::Resize();
+
+ // if the window is smaller than "title line height" + "control area",
+ // do nothing
+ if (GetOutputSizePixel().Height() <
+ (GetControlArea().GetHeight() + GetDataWindow().GetPosPixel().Y()))
+ return;
+
+ // the size of the control area
+ Point aPoint(GetControlArea().TopLeft());
+ sal_uInt16 nX = static_cast<sal_uInt16>(aPoint.X());
+
+ ArrangeControls(nX, static_cast<sal_uInt16>(aPoint.Y()));
+
+ if (!nX)
+ nX = USHRT_MAX;
+
+ bool bChanged = ReserveControlArea(nX);
+
+ //tdf#97731 if the reserved area changed size, give the controls a
+ //chance to adapt to the new size
+ if (bChanged)
+ {
+ nX = static_cast<sal_uInt16>(aPoint.X());
+ ArrangeControls(nX, static_cast<sal_uInt16>(aPoint.Y()));
+ }
+ }
+
+ void EditBrowseBox::ArrangeControls(sal_uInt16&, sal_uInt16)
+ {
+ }
+
+ CellController* EditBrowseBox::GetController(sal_Int32, sal_uInt16)
+ {
+ return nullptr;
+ }
+
+ void EditBrowseBox::ResizeController(CellControllerRef const & rController, const tools::Rectangle& rRect)
+ {
+ Point aPoint(rRect.TopLeft());
+ Size aSize(rRect.GetSize());
+ Control& rControl = rController->GetWindow();
+ auto nMinHeight = rControl.get_preferred_size().Height();
+ if (nMinHeight > aSize.Height())
+ {
+ auto nOffset = (nMinHeight - aSize.Height()) / 2;
+ aPoint.AdjustY(-nOffset);
+ aSize.setHeight(nMinHeight);
+ }
+ rControl.SetPosSizePixel(aPoint, aSize);
+ }
+
+ void EditBrowseBox::InitController(CellControllerRef&, sal_Int32, sal_uInt16)
+ {
+ }
+
+
+ void EditBrowseBox::CellModified()
+ {
+ }
+
+
+ bool EditBrowseBox::SaveModified()
+ {
+ return true;
+ }
+
+
+ void EditBrowseBox::DoubleClick(const BrowserMouseEvent& rEvt)
+ {
+ // when double clicking on the column, the optimum size will be calculated
+ sal_uInt16 nColId = rEvt.GetColumnId();
+ if (nColId != HandleColumnId)
+ SetColumnWidth(nColId, GetAutoColumnWidth(nColId));
+ }
+
+
+ sal_uInt32 EditBrowseBox::GetAutoColumnWidth(sal_uInt16 nColId)
+ {
+ sal_uInt32 nCurColWidth = GetColumnWidth(nColId);
+ sal_uInt32 nMinColWidth = CalcZoom(20); // minimum
+ sal_uInt32 nNewColWidth = nMinColWidth;
+ sal_Int32 nMaxRows = std::min(sal_Int32(GetVisibleRows()), GetRowCount());
+ sal_Int32 nLastVisRow = GetTopRow() + nMaxRows - 1;
+
+ if (GetTopRow() <= nLastVisRow) // calc the column with using the cell contents
+ {
+ for (tools::Long i = GetTopRow(); i <= nLastVisRow; ++i)
+ nNewColWidth = std::max(nNewColWidth,GetTotalCellWidth(i,nColId) + 12);
+
+ if (nNewColWidth == nCurColWidth) // size has not changed
+ nNewColWidth = GetDefaultColumnWidth(GetColumnTitle(nColId));
+ }
+ else
+ nNewColWidth = GetDefaultColumnWidth(GetColumnTitle(nColId));
+ return nNewColWidth;
+ }
+
+ sal_uInt32 EditBrowseBox::GetTotalCellWidth(sal_Int32, sal_uInt16)
+ {
+ return 0;
+ }
+
+ void EditBrowseBox::InvalidateHandleColumn()
+ {
+ tools::Rectangle aHdlFieldRect( GetFieldRectPixel( 0, 0 ));
+ tools::Rectangle aInvalidRect( Point(0,0), GetOutputSizePixel() );
+ aInvalidRect.SetRight( aHdlFieldRect.Right() );
+ Invalidate( aInvalidRect );
+ }
+
+ void EditBrowseBox::PaintTristate(const tools::Rectangle& rRect, const TriState& eState, bool _bEnabled) const
+ {
+ pCheckBoxPaint->SetState(eState);
+
+ pCheckBoxPaint->GetBox().set_sensitive(_bEnabled);
+
+ Size aBoxSize = pCheckBoxPaint->GetBox().get_preferred_size();
+ tools::Rectangle aRect(Point(rRect.Left() + ((rRect.GetWidth() - aBoxSize.Width()) / 2),
+ rRect.Top() + ((rRect.GetHeight() - aBoxSize.Height()) / 2)),
+ aBoxSize);
+ pCheckBoxPaint->SetPosSizePixel(aRect.TopLeft(), aRect.GetSize());
+
+ pCheckBoxPaint->Draw(GetDataWindow().GetOutDev(), aRect.TopLeft(), SystemTextColorFlags::NONE);
+ }
+
+ void EditBrowseBox::AsynchGetFocus()
+ {
+ if (nStartEvent)
+ Application::RemoveUserEvent(nStartEvent);
+
+ m_pFocusWhileRequest = Application::GetFocusWindow();
+ nStartEvent = Application::PostUserEvent(LINK(this,EditBrowseBox,StartEditHdl), nullptr, true);
+ }
+
+
+ void EditBrowseBox::SetBrowserFlags(EditBrowseBoxFlags nFlags)
+ {
+ if (m_nBrowserFlags == nFlags)
+ return;
+
+ bool RowPicturesChanges = ((m_nBrowserFlags & EditBrowseBoxFlags::NO_HANDLE_COLUMN_CONTENT) !=
+ (nFlags & EditBrowseBoxFlags::NO_HANDLE_COLUMN_CONTENT));
+ m_nBrowserFlags = nFlags;
+
+ if (RowPicturesChanges)
+ InvalidateStatusCell(GetCurRow());
+ }
+
+ inline void EditBrowseBox::EnableAndShow() const
+ {
+ Controller()->resume();
+ }
+
+ CellController::CellController(ControlBase* pW)
+ : pWindow(pW)
+ , bSuspended( true )
+ {
+
+ DBG_ASSERT(pWindow, "CellController::CellController: missing the window!");
+ DBG_ASSERT(!pWindow->IsVisible(), "CellController::CellController: window should not be visible!");
+ }
+
+ CellController::~CellController()
+ {
+ }
+
+ void CellController::suspend( )
+ {
+ DBG_ASSERT( bSuspended == !GetWindow().IsVisible(), "CellController::suspend: inconsistence!" );
+ if ( !isSuspended( ) )
+ {
+ CommitModifications();
+ GetWindow().Hide( );
+ GetWindow().Disable( );
+ bSuspended = true;
+ }
+ }
+
+ void CellController::resume( )
+ {
+ DBG_ASSERT( bSuspended == !GetWindow().IsVisible(), "CellController::resume: inconsistence!" );
+ if ( isSuspended( ) )
+ {
+ GetWindow().Enable( );
+ GetWindow().Show( );
+ bSuspended = false;
+ }
+ }
+
+ void CellController::CommitModifications()
+ {
+ // nothing to do in this base class
+ }
+
+ void CellController::ActivatingMouseEvent(const BrowserMouseEvent& /*rEvt*/, bool /*bUp*/)
+ {
+ // nothing to do in this base class
+ }
+
+ bool CellController::MoveAllowed(const KeyEvent&) const
+ {
+ return true;
+ }
+
+} // namespace svt
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */