Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/LibreOffice/svx/source/fmcomp/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 149 kB image not shown  

SSL gridcell.cxx

  Sprache: C
 

/* -*- 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 <memory>
#include <sal/log.hxx>
#include <fmprop.hxx>
#include <svx/strings.hrc>
#include <svx/fmtools.hxx>
#include <gridcell.hxx>
#include <gridcols.hxx>
#include <sdbdatacolumn.hxx>

#include <com/sun/star/awt/LineEndFormat.hpp>
#include <com/sun/star/awt/MouseWheelBehavior.hpp>
#include <com/sun/star/awt/VisualEffect.hpp>
#include <com/sun/star/container/XChild.hpp>
#include <com/sun/star/container/XIndexAccess.hpp>
#include <com/sun/star/form/FormComponentType.hpp>
#include <com/sun/star/form/XBoundComponent.hpp>
#include <com/sun/star/script/XEventAttacherManager.hpp>
#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
#include <com/sun/star/sdbc/DataType.hpp>
#include <com/sun/star/sdbc/SQLException.hpp>
#include <com/sun/star/sdbc/XRowSet.hpp>
#include <com/sun/star/sdbc/XStatement.hpp>
#include <com/sun/star/util/XNumberFormatsSupplier.hpp>
#include <com/sun/star/util/XNumberFormatter.hpp>
#include <com/sun/star/util/Time.hpp>
#include <com/sun/star/util/Date.hpp>

#include <comphelper/numbers.hxx>
#include <comphelper/property.hxx>
#include <comphelper/servicehelper.hxx>
#include <comphelper/string.hxx>
#include <comphelper/types.hxx>
#include <connectivity/formattedcolumnvalue.hxx>
#include <i18nlangtag/lang.h>
#include <o3tl/safeint.hxx>
#include <svl/numformat.hxx>
#include <svl/numuno.hxx>
#include <svx/dialmgr.hxx>
#include <toolkit/helper/listenermultiplexer.hxx>
#include <toolkit/helper/vclunohelper.hxx>
#include <tools/debug.hxx>
#include <tools/fract.hxx>
#include <comphelper/diagnose_ex.hxx>
#include <vcl/settings.hxx>
#include <vcl/svapp.hxx>
#include <connectivity/dbtools.hxx>
#include <connectivity/dbconversion.hxx>
#include <connectivity/sqlnode.hxx>

using namespace ::connectivity;
using namespace ::svxform;
using namespace ::comphelper;
using namespace ::svt;
using namespace ::com::sun::star;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::sdbc;
using namespace ::com::sun::star::sdbcx;
using namespace ::com::sun::star::sdb;
using namespace ::com::sun::star::beans;
using namespace ::com::sun::star::form;
using namespace ::dbtools::DBTypeConversion;
using namespace ::dbtools;

using ::com::sun::star::util::XNumberFormatter;

constexpr OUString INVALIDTEXT = u"###"_ustr;
constexpr OUString OBJECTTEXT = u"<OBJECT>"_ustr;


//= helper

namespace
{
    LineEnd getModelLineEndSetting( const Reference< XPropertySet >& _rxModel )
    {
        LineEnd eFormat = LINEEND_LF;

        try
        {
            sal_Int16 nLineEndFormat = awt::LineEndFormat::LINE_FEED;

            Reference< XPropertySetInfo > xPSI;
            if ( _rxModel.is() )
                xPSI = _rxModel->getPropertySetInfo();

            OSL_ENSURE( xPSI.is(), "getModelLineEndSetting: invalid column model!" );
            if ( xPSI.is() && xPSI->hasPropertyByName( FM_PROP_LINEENDFORMAT ) )
            {
                OSL_VERIFY( _rxModel->getPropertyValue( FM_PROP_LINEENDFORMAT ) >>= nLineEndFormat );

                switch ( nLineEndFormat )
                {
                case awt::LineEndFormat::CARRIAGE_RETURN:            eFormat = LINEEND_CR; break;
                case awt::LineEndFormat::LINE_FEED:                  eFormat = LINEEND_LF; break;
                case awt::LineEndFormat::CARRIAGE_RETURN_LINE_FEED:  eFormat = LINEEND_CRLF; break;
                default:
                    OSL_FAIL( "getModelLineEndSetting: what's this?" );
                }
            }
        }
        catchconst Exception& )
        {
            TOOLS_WARN_EXCEPTION( "svx""getModelLineEndSetting" );
        }
        return eFormat;
    }
}


//= DbGridColumn


CellControllerRef DbGridColumn::s_xEmptyController;


void DbGridColumn::CreateControl(sal_Int32 _nFieldPos, const Reference< css::beans::XPropertySet >& xField, sal_Int32 nTypeId)
{
    Clear();

    m_nTypeId = static_cast<sal_Int16>(nTypeId);
    if (xField != m_xField)
    {
        // initial setting
        m_xField = xField;
        xField->getPropertyValue(FM_PROP_FORMATKEY) >>= m_nFormatKey;
        m_nFieldPos   = static_cast<sal_Int16>(_nFieldPos);
        m_bReadOnly   = ::comphelper::getBOOL(xField->getPropertyValue(FM_PROP_ISREADONLY));
        m_bAutoValue  = ::comphelper::getBOOL(xField->getPropertyValue(FM_PROP_AUTOINCREMENT));
        m_nFieldType  = static_cast<sal_Int16>(::comphelper::getINT32(xField->getPropertyValue(FM_PROP_FIELDTYPE)));

        switch (m_nFieldType)
        {
            case DataType::DATE:
            case DataType::TIME:
            case DataType::TIMESTAMP:
            case DataType::BIT:
            case DataType::BOOLEAN:
            case DataType::TINYINT:
            case DataType::SMALLINT:
            case DataType::INTEGER:
            case DataType::BIGINT:
            case DataType::FLOAT:
            case DataType::REAL:
            case DataType::DOUBLE:
            case DataType::NUMERIC:
            case DataType::DECIMAL:
                m_nAlign = css::awt::TextAlign::RIGHT;
                m_bNumeric = true;
                break;
            default:
                m_nAlign = css::awt::TextAlign::LEFT;
                break;
        }
    }

    std::unique_ptr<DbCellControl> pCellControl;
    if (m_rParent.IsFilterMode())
    {
        pCellControl.reset(new DbFilterField(m_rParent.getContext(),*this));
    }
    else
    {

        switch (nTypeId)
        {
            case TYPE_CHECKBOX: pCellControl.reset(new DbCheckBox(*this));   break;
            case TYPE_COMBOBOX: pCellControl.reset(new DbComboBox(*this)); break;
            case TYPE_CURRENCYFIELD: pCellControl.reset(new DbCurrencyField(*this)); break;
            case TYPE_DATEFIELD: pCellControl.reset(new DbDateField(*this)); break;
            case TYPE_LISTBOX: pCellControl.reset(new DbListBox(*this)); break;
            case TYPE_NUMERICFIELD: pCellControl.reset(new DbNumericField(*this)); break;
            case TYPE_PATTERNFIELD: pCellControl.reset(new DbPatternField( *this, m_rParent.getContext() )); break;
            case TYPE_TEXTFIELD: pCellControl.reset(new DbTextField(*this)); break;
            case TYPE_TIMEFIELD: pCellControl.reset(new DbTimeField(*this)); break;
            case TYPE_FORMATTEDFIELD: pCellControl.reset(new DbFormattedField(*this)); break;
            default:
                OSL_FAIL("DbGridColumn::CreateControl: Unknown Column");
                return;
        }

    }
    Reference< XRowSet >  xCur;
    if (m_rParent.getDataSource())
        xCur.set(Reference< XInterface >(*m_rParent.getDataSource()), UNO_QUERY);
        // TODO : the cursor wrapper should use an XRowSet interface, too

    pCellControl->Init( m_rParent.GetDataWindow(), xCur );

    // now create the control wrapper
    auto pTempCellControl = pCellControl.get();
    if (m_rParent.IsFilterMode())
        m_pCell = new FmXFilterCell(this, std::unique_ptr<DbFilterField>(static_cast<DbFilterField*>(pCellControl.release())));
    else
    {
        switch (nTypeId)
        {
            case TYPE_CHECKBOX: m_pCell = new FmXCheckBoxCell( this, std::move(pCellControl) );  break;
            case TYPE_LISTBOX: m_pCell = new FmXListBoxCell( this, std::move(pCellControl) );    break;
            case TYPE_COMBOBOX: m_pCell = new FmXComboBoxCell( this, std::move(pCellControl) );    break;
            default:
                m_pCell = new FmXEditCell( this, std::move(pCellControl) );
        }
    }
    m_pCell->init();

    impl_toggleScriptManager_nothrow( true );

    // only if we use have a bound field, we use a controller for displaying the
    // window in the grid
    if (m_xField.is())
        m_xController = pTempCellControl->CreateController();
}


void DbGridColumn::impl_toggleScriptManager_nothrow( bool _bAttach )
{
    try
    {
        Reference< container::XChild > xChild( m_xModel, UNO_QUERY_THROW );
        Reference< script::XEventAttacherManager > xManager( xChild->getParent(), UNO_QUERY_THROW );
        Reference< container::XIndexAccess > xContainer( xChild->getParent(), UNO_QUERY_THROW );

        sal_Int32 nIndexInParent( getElementPos( xContainer, m_xModel ) );

        Reference< XInterface > xCellInterface( *m_pCell, UNO_QUERY );
        if ( _bAttach )
            xManager->attach( nIndexInParent, xCellInterface, Any( xCellInterface ) );
        else
            xManager->detach( nIndexInParent, xCellInterface );
    }
    catchconst Exception& )
    {
        DBG_UNHANDLED_EXCEPTION("svx");
    }
}

void DbGridColumn::UpdateFromField(const DbGridRow* pRow, const Reference< XNumberFormatter >& xFormatter)
{
    if (FmXFilterCell* pCell = dynamic_cast<FmXFilterCell*>(m_pCell.get()))
        pCell->Update();
    else if (pRow && pRow->IsValid() && m_nFieldPos >= 0 && m_pCell.is() && pRow->HasField(m_nFieldPos))
    {
        dynamic_cast<FmXDataCell&>(*m_pCell).UpdateFromField( pRow->GetField( m_nFieldPos ).getColumn(), xFormatter  );
    }
}

bool DbGridColumn::Commit()
{
    bool bResult = true;
    if (!m_bInSave && m_pCell.is())
    {
        m_bInSave = true;
        bResult = m_pCell->Commit();

        // store the data into the model
        FmXDataCell* pDataCell = dynamic_cast<FmXDataCell*>( m_pCell.get() );
        if (bResult && pDataCell)
        {
            Reference< css::form::XBoundComponent >  xComp(m_xModel, UNO_QUERY);
            if (xComp.is())
                bResult = xComp->commit();
        }
        m_bInSave = false;
    }
    return bResult;
}

DbGridColumn::~DbGridColumn()
{
    Clear();
}

void DbGridColumn::setModel(const css::uno::Reference< css::beans::XPropertySet >&  _xModel)
{
    if ( m_pCell.is() )
        impl_toggleScriptManager_nothrow( false );

    m_xModel = _xModel;

    if ( m_pCell.is() )
        impl_toggleScriptManager_nothrow( true );
}


void DbGridColumn::Clear()
{
    if ( m_pCell.is() )
    {
        impl_toggleScriptManager_nothrow( false );

        m_pCell->dispose();
        m_pCell.clear();
    }

    m_xController = nullptr;
    m_xField = nullptr;

    m_nFormatKey = 0;
    m_nFieldPos = -1;
    m_bReadOnly = true;
    m_bAutoValue = false;
    m_nFieldType = DataType::OTHER;
}


sal_Int16 DbGridColumn::SetAlignment(sal_Int16 _nAlign)
{
    if (_nAlign == -1)
    {   // 'Standard'
        if (m_xField.is())
        {
            sal_Int32 nType = 0;
            m_xField->getPropertyValue(FM_PROP_FIELDTYPE) >>= nType;

            switch (nType)
            {
                case DataType::NUMERIC:
                case DataType::DECIMAL:
                case DataType::DOUBLE:
                case DataType::REAL:
                case DataType::BIGINT:
                case DataType::INTEGER:
                case DataType::SMALLINT:
                case DataType::TINYINT:
                case DataType::DATE:
                case DataType::TIME:
                case DataType::TIMESTAMP:
                    _nAlign = css::awt::TextAlign::RIGHT;
                    break;
                case DataType::BIT:
                case DataType::BOOLEAN:
                    _nAlign = css::awt::TextAlign::CENTER;
                    break;
                default:
                    _nAlign = css::awt::TextAlign::LEFT;
                    break;
            }
        }
        else
            _nAlign = css::awt::TextAlign::LEFT;
    }

    m_nAlign = _nAlign;
    if (m_pCell.is() && m_pCell->isAlignedController())
        m_pCell->AlignControl(m_nAlign);

    return m_nAlign;
}


sal_Int16 DbGridColumn::SetAlignmentFromModel(sal_Int16 nStandardAlign)
{
    Any aAlign( m_xModel->getPropertyValue(FM_PROP_ALIGN));
    if (aAlign.hasValue())
    {
        sal_Int16 nTest = sal_Int16();
        if (aAlign >>= nTest)
            nStandardAlign = nTest;
    }
    return SetAlignment(nStandardAlign);
}


void DbGridColumn::setLock(bool _bLock)
{
    if (m_bLocked == _bLock)
        return;
    m_bLocked = _bLock;

    // is the column we represent active ?
    if (m_bHidden)
        return;     // no, it isn't (or at least it shouldn't be ...)

    if (m_rParent.GetCurColumnId() == m_nId)
    {
        m_rParent.DeactivateCell();
        m_rParent.ActivateCell(m_rParent.GetCurRow(), m_rParent.GetCurColumnId());
    }
}


OUString DbGridColumn::GetCellText(const DbGridRow* pRow, const Reference< XNumberFormatter >& xFormatter) const
{
    OUString aText;
    if (m_pCell.is() && dynamic_cast<const FmXFilterCell*>( m_pCell.get() ) !=  nullptr)
        return aText;

    if (!pRow || !pRow->IsValid())
        aText = INVALIDTEXT;
    else if (pRow->HasField(m_nFieldPos))
    {
        aText = GetCellText( pRow->GetField( m_nFieldPos ).getColumn(), xFormatter );
    }
    return aText;
}

OUString DbGridColumn::GetCellText(const Reference< css::sdb::XColumn >& xField, const Reference< XNumberFormatter >& xFormatter) const
{
    OUString aText;
    if (xField.is())
    {
        FmXTextCell* pTextCell = dynamic_cast<FmXTextCell*>( m_pCell.get() );
        if (pTextCell)
            aText = pTextCell->GetText(xField, xFormatter);
        else if (m_bObject)
            aText = OBJECTTEXT;
    }
    return aText;
}

Reference< css::sdb::XColumn >  DbGridColumn::GetCurrentFieldValue() const
{
    Reference< css::sdb::XColumn >  xField;
    const DbGridRowRef xRow = m_rParent.GetCurrentRow();
    if (xRow.is() && xRow->HasField(m_nFieldPos))
    {
        xField = xRow->GetField(m_nFieldPos).getColumn();
    }
    return xField;
}


void DbGridColumn::Paint(OutputDevice& rDev,
                         const tools::Rectangle& rRect,
                         const DbGridRow* pRow,
                         const Reference< XNumberFormatter >& xFormatter)
{
    bool bEnabled = ( rDev.GetOutDevType() != OUTDEV_WINDOW )
                ||  ( rDev.GetOwnerWindow()->IsEnabled() );

    FmXDataCell* pDataCell = dynamic_cast<FmXDataCell*>( m_pCell.get() );
    if (pDataCell)
    {
        if (!pRow || !pRow->IsValid())
        {
            DrawTextFlags nStyle = DrawTextFlags::Clip | DrawTextFlags::Center;
            if ( !bEnabled )
                nStyle |= DrawTextFlags::Disable;

            rDev.DrawText(rRect, INVALIDTEXT, nStyle);
        }
        else if (m_bAutoValue && pRow->IsNew())
        {
            DrawTextFlags nStyle = DrawTextFlags::Clip | DrawTextFlags::VCenter;
            if ( !bEnabled )
                nStyle |= DrawTextFlags::Disable;

            switch (GetAlignment())
            {
                case css::awt::TextAlign::RIGHT:
                    nStyle |= DrawTextFlags::Right;
                    break;
                case css::awt::TextAlign::CENTER:
                    nStyle |= DrawTextFlags::Center;
                    break;
                default:
                    nStyle |= DrawTextFlags::Left;
            }

            rDev.DrawText(rRect, SvxResId(RID_STR_AUTOFIELD), nStyle);
        }
        else if (pRow->HasField(m_nFieldPos))
        {
            pDataCell->PaintFieldToCell(rDev, rRect, pRow->GetField( m_nFieldPos ).getColumn(), xFormatter);
        }
    }
    else if (!m_pCell.is())
    {
        if (!pRow || !pRow->IsValid())
        {
            DrawTextFlags nStyle = DrawTextFlags::Clip | DrawTextFlags::Center;
            if ( !bEnabled )
                nStyle |= DrawTextFlags::Disable;

            rDev.DrawText(rRect, INVALIDTEXT, nStyle);
        }
        else if (pRow->HasField(m_nFieldPos) && m_bObject)
        {
            DrawTextFlags nStyle = DrawTextFlags::Clip | DrawTextFlags::Center;
            if ( !bEnabled )
                nStyle |= DrawTextFlags::Disable;
            rDev.DrawText(rRect, OBJECTTEXT, nStyle);
        }
    }
    else if ( auto pFilterCell = dynamic_cast<FmXFilterCell*>( m_pCell.get() ) )
        pFilterCell->PaintCell( rDev, rRect );
}


void DbGridColumn::ImplInitWindow( vcl::Window const & rParent, const InitWindowFacet _eInitWhat )
{
    if ( m_pCell.is() )
        m_pCell->ImplInitWindow( rParent, _eInitWhat );
}


//= cell controls


DbCellControl::DbCellControl( DbGridColumn& _rColumn )
    :OPropertyChangeListener()
    ,m_bTransparent( false )
    ,m_bAlignedController( true )
    ,m_bAccessingValueProperty( false )
    ,m_rColumn( _rColumn )
    ,m_pPainter( nullptr )
    ,m_pWindow( nullptr )
{
    const Reference< XPropertySet >& xColModelProps = _rColumn.getModel();
    if ( !xColModelProps.is() )
        return;

    // if our model's format key changes we want to propagate the new value to our windows
    m_pModelChangeBroadcaster = new ::comphelper::OPropertyChangeMultiplexer(this, _rColumn.getModel());

    // be listener for some common properties
    implDoPropertyListening( FM_PROP_READONLY, false );
    implDoPropertyListening( FM_PROP_ENABLED, false );

    // add as listener for all known "value" properties
    implDoPropertyListening( FM_PROP_VALUE, false );
    implDoPropertyListening( FM_PROP_STATE, false );
    implDoPropertyListening( FM_PROP_TEXT, false );
    implDoPropertyListening( FM_PROP_EFFECTIVE_VALUE, false );
    implDoPropertyListening( FM_PROP_SELECT_SEQ, false );
    implDoPropertyListening( FM_PROP_DATE, false );
    implDoPropertyListening( FM_PROP_TIME, false );

    // be listener at the bound field as well
    try
    {
        Reference< XPropertySetInfo > xPSI( xColModelProps->getPropertySetInfo(), UNO_SET_THROW );
        if ( xPSI->hasPropertyByName( FM_PROP_BOUNDFIELD ) )
        {
            Reference< XPropertySet > xField;
            xColModelProps->getPropertyValue( FM_PROP_BOUNDFIELD ) >>= xField;
            if ( xField.is() )
            {
                m_pFieldChangeBroadcaster = new ::comphelper::OPropertyChangeMultiplexer(this, xField);
                m_pFieldChangeBroadcaster->addProperty( FM_PROP_ISREADONLY );
            }
        }
    }
    catchconst Exception& )
    {
        TOOLS_WARN_EXCEPTION( "svx""DbCellControl::doPropertyListening" );
    }
}


void DbCellControl::implDoPropertyListening(const OUString& _rPropertyName, bool _bWarnIfNotExistent)
{
    try
    {
        Reference< XPropertySet > xColModelProps = m_rColumn.getModel();
        Reference< XPropertySetInfo > xPSI;
        if ( xColModelProps.is() )
            xPSI = xColModelProps->getPropertySetInfo();

        DBG_ASSERT( !_bWarnIfNotExistent || ( xPSI.is() && xPSI->hasPropertyByName( _rPropertyName ) ),
            "DbCellControl::doPropertyListening: no property set info or non-existent property!" );

        if ( xPSI.is() && xPSI->hasPropertyByName( _rPropertyName ) )
            m_pModelChangeBroadcaster->addProperty( _rPropertyName );
    }
    catchconst Exception& )
    {
        TOOLS_WARN_EXCEPTION( "svx""DbCellControl::doPropertyListening" );
    }
}


void DbCellControl::doPropertyListening(const OUString& _rPropertyName)
{
    implDoPropertyListening( _rPropertyName, true );
}

static void lcl_clearBroadCaster(rtl::Reference<::comphelper::OPropertyChangeMultiplexer>& _pBroadcaster)
{
    if ( _pBroadcaster.is() )
    {
        _pBroadcaster->dispose();
        _pBroadcaster.clear();
        // no delete, this is done implicitly
    }
}

DbCellControl::~DbCellControl()
{
    lcl_clearBroadCaster(m_pModelChangeBroadcaster);
    lcl_clearBroadCaster(m_pFieldChangeBroadcaster);

    m_pWindow.disposeAndClear();
    m_pPainter.disposeAndClear();
}

void DbCellControl::implValuePropertyChanged( )
{
    OSL_ENSURE( !isValuePropertyLocked(),
        "DbCellControl::implValuePropertyChanged: not to be called with the value property locked!" );

    if ( m_pWindow )
    {
        if ( m_rColumn.getModel().is() )
            updateFromModel( m_rColumn.getModel() );
    }
}


void DbCellControl::implAdjustGenericFieldSetting( const Reference< XPropertySet >& /*_rxModel*/ )
{
    // nothing to do here
}


void DbCellControl::_propertyChanged(const PropertyChangeEvent& _rEvent)
{
    SolarMutexGuard aGuard;

    Reference< XPropertySet > xSourceProps( _rEvent.Source, UNO_QUERY );

    if  (   _rEvent.PropertyName == FM_PROP_VALUE
        ||  _rEvent.PropertyName == FM_PROP_STATE
        ||  _rEvent.PropertyName == FM_PROP_TEXT
        ||  _rEvent.PropertyName == FM_PROP_EFFECTIVE_VALUE
        ||  _rEvent.PropertyName == FM_PROP_SELECT_SEQ
        ||  _rEvent.PropertyName == FM_PROP_DATE
        ||  _rEvent.PropertyName == FM_PROP_TIME
        )
    {   // it was one of the known "value" properties
        if ( !isValuePropertyLocked() )
        {
            implValuePropertyChanged( );
        }
    }
    else if ( _rEvent.PropertyName == FM_PROP_READONLY )
    {
        implAdjustReadOnly( xSourceProps, true);
    }
    else if ( _rEvent.PropertyName == FM_PROP_ISREADONLY )
    {
        bool bReadOnly = true;
        _rEvent.NewValue >>= bReadOnly;
        m_rColumn.SetReadOnly(bReadOnly);
        implAdjustReadOnly( xSourceProps, false);
    }
    else if ( _rEvent.PropertyName == FM_PROP_ENABLED )
    {
        implAdjustEnabled( xSourceProps );
    }
    else
        implAdjustGenericFieldSetting( xSourceProps );
}

bool DbCellControl::Commit()
{
    // lock the listening for value property changes
    lockValueProperty();
    // commit the content of the control into the model's value property
    bool bReturn = false;
    try
    {
        bReturn = commitControl();
    }
    catchconst Exception& )
    {
        DBG_UNHANDLED_EXCEPTION("svx");
    }
    // unlock the listening for value property changes
    unlockValueProperty();
    // outta here
    return bReturn;
}

void DbCellControl::ImplInitWindow( vcl::Window const & rParent, const InitWindowFacet _eInitWhat )
{
    svt::ControlBase* pWindows[] = { m_pPainter, m_pWindow };

    if (_eInitWhat & InitWindowFacet::WritingMode)
    {
        for (svt::ControlBase* pWindow : pWindows)
        {
            if (pWindow)
                pWindow->EnableRTL(rParent.IsRTLEnabled());
        }
    }

    if (_eInitWhat & InitWindowFacet::Font)
    {
        const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
        const Fraction& rZoom = rParent.GetZoom();

        for (svt::ControlBase* pWindow : pWindows)
        {
            if (!pWindow)
                continue;

            vcl::Font aFont = rStyleSettings.GetFieldFont();
            aFont.SetTransparent(isTransparent());

            if (rParent.IsControlFont())
                aFont.Merge(rParent.GetControlFont());

            if (rZoom.GetNumerator() != rZoom.GetDenominator())
            {
                Size aSize = aFont.GetFontSize();
                aSize.setWidth(std::round(double(aSize.Width() * rZoom)));
                aSize.setHeight(std::round(double(aSize.Height() * rZoom)));
                aFont.SetFontSize(aSize);
            }

            pWindow->SetPointFont(aFont);
        }
    }

    if ((_eInitWhat & InitWindowFacet::Font) || (_eInitWhat & InitWindowFacet::Foreground))
    {
        Color aTextColor(rParent.IsControlForeground() ? rParent.GetControlForeground() : rParent.GetTextColor());

        bool bTextLineColor = rParent.IsTextLineColor();
        Color aTextLineColor(rParent.GetTextLineColor());

        for (svt::ControlBase* pWindow : pWindows)
        {
            if (pWindow)
            {
                pWindow->SetTextColor(aTextColor);
                if (rParent.IsControlForeground())
                    pWindow->SetControlForeground(aTextColor);

                if (bTextLineColor)
                    pWindow->SetTextLineColor();
                else
                    pWindow->SetTextLineColor(aTextLineColor);
            }
        }
    }

    if (!(_eInitWhat & InitWindowFacet::Background))
        return;

    if (rParent.IsControlBackground())
    {
        Color aColor(rParent.GetControlBackground());
        for (svt::ControlBase* pWindow : pWindows)
        {
            if (pWindow)
            {
                if (isTransparent())
                    pWindow->SetBackground();
                else
                {
                    pWindow->SetBackground(aColor);
                    pWindow->SetControlBackground(aColor);
                }
                pWindow->GetOutDev()->SetFillColor(aColor);
            }
        }
    }
    else
    {
        if (m_pPainter)
        {
            if (isTransparent())
                m_pPainter->SetBackground();
            else
                m_pPainter->SetBackground(rParent.GetBackground());
            m_pPainter->GetOutDev()->SetFillColor(rParent.GetOutDev()->GetFillColor());
        }

        if (m_pWindow)
        {
            if (isTransparent())
                m_pWindow->SetBackground(rParent.GetBackground());
            else
                m_pWindow->GetOutDev()->SetFillColor(rParent.GetOutDev()->GetFillColor());
        }
    }
}

void DbCellControl::implAdjustReadOnly( const Reference< XPropertySet >& _rxModel,bool i_bReadOnly )
{
    DBG_ASSERT( m_pWindow, "DbCellControl::implAdjustReadOnly: not to be called without window!" );
    DBG_ASSERT( _rxModel.is(), "DbCellControl::implAdjustReadOnly: invalid model!" );
    if ( !(m_pWindow && _rxModel.is()) )
        return;

    bool bReadOnly = m_rColumn.IsReadOnly();
    if ( !bReadOnly )
    {
        _rxModel->getPropertyValue( i_bReadOnly ? FM_PROP_READONLY : FM_PROP_ISREADONLY) >>= bReadOnly;
    }
    m_pWindow->SetEditableReadOnly(bReadOnly);
}

void DbCellControl::implAdjustEnabled( const Reference< XPropertySet >& _rxModel )
{
    DBG_ASSERT( m_pWindow, "DbCellControl::implAdjustEnabled: not to be called without window!" );
    DBG_ASSERT( _rxModel.is(), "DbCellControl::implAdjustEnabled: invalid model!" );
    if ( m_pWindow && _rxModel.is() )
    {
        bool bEnable = true;
        _rxModel->getPropertyValue( FM_PROP_ENABLED ) >>= bEnable;
        m_pWindow->Enable( bEnable );
    }
}

void DbCellControl::Init(BrowserDataWin& rParent, const Reference< XRowSet >& _rxCursor)
{
    ImplInitWindow( rParent, InitWindowFacet::All );

    if ( m_pWindow )
    {
        // align the control
        if ( isAlignedController() )
            AlignControl( m_rColumn.GetAlignment() );

        try
        {
            // some other common properties
            Reference< XPropertySet > xModel( m_rColumn.getModel(), UNO_SET_THROW );
            Reference< XPropertySetInfo > xModelPSI( xModel->getPropertySetInfo(), UNO_SET_THROW );

            if ( xModelPSI->hasPropertyByName( FM_PROP_READONLY ) )
            {
                implAdjustReadOnly( xModel,true );
            }

            if ( xModelPSI->hasPropertyByName( FM_PROP_ENABLED ) )
            {
                implAdjustEnabled( xModel );
            }

            if ( xModelPSI->hasPropertyByName( FM_PROP_MOUSE_WHEEL_BEHAVIOR ) )
            {
                sal_Int16 nWheelBehavior = css::awt::MouseWheelBehavior::SCROLL_FOCUS_ONLY;
                OSL_VERIFY( xModel->getPropertyValue( FM_PROP_MOUSE_WHEEL_BEHAVIOR ) >>= nWheelBehavior );
                MouseWheelBehaviour nVclSetting = MouseWheelBehaviour::FocusOnly;
                switch ( nWheelBehavior )
                {
                case css::awt::MouseWheelBehavior::SCROLL_DISABLED:   nVclSetting = MouseWheelBehaviour::Disable; break;
                case css::awt::MouseWheelBehavior::SCROLL_FOCUS_ONLY: nVclSetting = MouseWheelBehaviour::FocusOnly; break;
                case css::awt::MouseWheelBehavior::SCROLL_ALWAYS:     nVclSetting = MouseWheelBehaviour::ALWAYS; break;
                default:
                    OSL_FAIL( "DbCellControl::Init: invalid MouseWheelBehavior!" );
                    break;
                }

                AllSettings aSettings = m_pWindow->GetSettings();
                MouseSettings aMouseSettings = aSettings.GetMouseSettings();
                aMouseSettings.SetWheelBehavior( nVclSetting );
                aSettings.SetMouseSettings( aMouseSettings );
                m_pWindow->SetSettings( aSettings, true );
            }
        }
        catchconst Exception& )
        {
            DBG_UNHANDLED_EXCEPTION("svx");
        }
    }
    m_xCursor = _rxCursor;
    if ( m_rColumn.getModel().is() )
        updateFromModel( m_rColumn.getModel() );
}


void DbCellControl::SetTextLineColor()
{
    if (m_pWindow)
        m_pWindow->SetTextLineColor();
    if (m_pPainter)
        m_pPainter->SetTextLineColor();
}


void DbCellControl::SetTextLineColor(const Color& _rColor)
{
    if (m_pWindow)
        m_pWindow->SetTextLineColor(_rColor);
    if (m_pPainter)
        m_pPainter->SetTextLineColor(_rColor);
}

namespace
{
    void lcl_implAlign( vcl::Window* _pWindow, WinBits _nAlignmentBit )
    {
        if (EditControlBase* pControl = dynamic_cast<EditControlBase*>(_pWindow))
        {
            switch (_nAlignmentBit)
            {
                case WB_LEFT:
                    pControl->get_widget().set_alignment(TxtAlign::Left);
                    break;
                case WB_CENTER:
                    pControl->get_widget().set_alignment(TxtAlign::Center);
                    break;
                case WB_RIGHT:
                    pControl->get_widget().set_alignment(TxtAlign::Right);
                    break;
            }
            return;
        }

        WinBits nStyle = _pWindow->GetStyle();
        nStyle &= ~(WB_LEFT | WB_RIGHT | WB_CENTER);
        _pWindow->SetStyle( nStyle | _nAlignmentBit );
    }
}

void DbCellControl::AlignControl(sal_Int16 nAlignment)
{
    WinBits nAlignmentBit = 0;
    switch (nAlignment)
    {
        case css::awt::TextAlign::RIGHT:
            nAlignmentBit = WB_RIGHT;
            break;
        case css::awt::TextAlign::CENTER:
            nAlignmentBit = WB_CENTER;
            break;
        default:
            nAlignmentBit = WB_LEFT;
            break;
    }
    lcl_implAlign( m_pWindow, nAlignmentBit );
    if ( m_pPainter )
        lcl_implAlign( m_pPainter, nAlignmentBit );
}

void DbCellControl::PaintCell(OutputDevice& rDev, const tools::Rectangle& rRect)
{
    m_pPainter->SetSizePixel(rRect.GetSize());
    m_pPainter->Draw(&rDev, rRect.TopLeft(), SystemTextColorFlags::NONE);
}

void DbCellControl::PaintFieldToCell( OutputDevice& _rDev, const tools::Rectangle&&nbsp;_rRect, const Reference< XColumn >& _rxField, const Reference< XNumberFormatter >& ;_rxFormatter )
{
    m_pPainter->SetText( GetFormatText( _rxField, _rxFormatter ) );
    PaintCell( _rDev, _rRect );
}

double DbCellControl::GetValue(const Reference< css::sdb::XColumn >& _rxField, const Reference< XNumberFormatter >& xFormatter) const
{
    double fValue = 0;
    if (m_rColumn.IsNumeric())
    {
        try
        {
            fValue = _rxField->getDouble();
        }
        catch(const Exception&) { }
    }
    else
    {
        bool bSuccess = false;
        try
        {
            fValue = _rxField->getDouble();
            bSuccess = true;
        }
        catch(const Exception&) { }
        if (!bSuccess)
        {
            try
            {
                fValue = xFormatter->convertStringToNumber(m_rColumn.GetKey(), _rxField->getString());
            }
            catch(const Exception&) { }
        }
    }
    return fValue;
}

void DbCellControl::invalidatedController()
{
    m_rColumn.GetParent().refreshController(m_rColumn.GetId(), DbGridControl::GrantControlAccess());
}

// CellModels

DbLimitedLengthField::DbLimitedLengthField( DbGridColumn& _rColumn )
    :DbCellControl( _rColumn )
{
    doPropertyListening( FM_PROP_MAXTEXTLEN );
}


void DbLimitedLengthField::implAdjustGenericFieldSetting( const Reference< XPropertySet >& _rxModel )
{
    DBG_ASSERT( m_pWindow, "DbLimitedLengthField::implAdjustGenericFieldSetting: not to be called without window!" );
    DBG_ASSERT( _rxModel.is(), "DbLimitedLengthField::implAdjustGenericFieldSetting: invalid model!" );
    if ( m_pWindow && _rxModel.is() )
    {
        sal_Int16 nMaxLen = 0;
        _rxModel->getPropertyValue( FM_PROP_MAXTEXTLEN ) >>= nMaxLen;
        implSetMaxTextLen( nMaxLen );
    }
}

void DbLimitedLengthField::implSetEffectiveMaxTextLen(sal_Int32 nMaxLen)
{
    dynamic_cast<EditControlBase&>(*m_pWindow).get_widget().set_max_length(nMaxLen);
    if (m_pPainter)
        dynamic_cast<EditControlBase&>(*m_pPainter).get_widget().set_max_length(nMaxLen);
}

DbTextField::DbTextField(DbGridColumn& _rColumn)
            :DbLimitedLengthField(_rColumn)
            ,m_bIsMultiLineEdit(false)
{
}

DbTextField::~DbTextField( )
{
    m_pPainterImplementation.reset();
    m_pEdit.reset();
}

void DbTextField::Init(BrowserDataWin& rParent, const Reference< XRowSet >& xCursor)
{
    sal_Int16 nAlignment = m_rColumn.SetAlignmentFromModel(-1);

    Reference< XPropertySet > xModel( m_rColumn.getModel() );

    bool bLeftAlign = true;

    // is this a multi-line field?
    bool bIsMultiLine = false;
    try
    {
        if ( xModel.is() )
        {
            OSL_VERIFY( xModel->getPropertyValue( FM_PROP_MULTILINE ) >>= bIsMultiLine );
        }
    }
    catchconst Exception& )
    {
        TOOLS_WARN_EXCEPTION("svx",
                             "caught an exception while determining the multi-line capabilities!");
    }

    m_bIsMultiLineEdit = bIsMultiLine;
    if ( bIsMultiLine )
    {
        auto xEditControl = VclPtr<MultiLineTextCell>::Create(&rParent);
        auto xEditPainter = VclPtr<MultiLineTextCell>::Create(&rParent);

        switch (nAlignment)
        {
            case awt::TextAlign::RIGHT:
                xEditControl->get_widget().set_alignment(TxtAlign::Right);
                xEditPainter->get_widget().set_alignment(TxtAlign::Right);
                bLeftAlign = false;
                break;
            case awt::TextAlign::CENTER:
                xEditControl->get_widget().set_alignment(TxtAlign::Center);
                xEditPainter->get_widget().set_alignment(TxtAlign::Center);
                bLeftAlign = false;
                break;
        }

        m_pWindow = xEditControl;
        m_pEdit.reset(new MultiLineEditImplementation(*xEditControl));

        m_pPainter = xEditPainter;
        m_pPainterImplementation.reset(new MultiLineEditImplementation(*xEditPainter));
    }
    else
    {
        auto xEditControl = VclPtr<EditControl>::Create(&rParent);
        auto xEditPainter = VclPtr<EditControl>::Create(&rParent);

        switch (nAlignment)
        {
            case awt::TextAlign::RIGHT:
                xEditControl->get_widget().set_alignment(TxtAlign::Right);
                xEditPainter->get_widget().set_alignment(TxtAlign::Right);
                bLeftAlign = false;
                break;
            case awt::TextAlign::CENTER:
                xEditControl->get_widget().set_alignment(TxtAlign::Center);
                xEditPainter->get_widget().set_alignment(TxtAlign::Center);
                bLeftAlign = false;
                break;
        }

        m_pWindow = xEditControl;
        m_pEdit.reset(new EntryImplementation(*xEditControl));

        m_pPainter = xEditPainter;
        m_pPainterImplementation.reset(new EntryImplementation(*xEditPainter));
    }

    if (bLeftAlign)
    {
        // this is so that when getting the focus, the selection is oriented left-to-right
        AllSettings aSettings = m_pWindow->GetSettings();
        StyleSettings aStyleSettings = aSettings.GetStyleSettings();
        aStyleSettings.SetSelectionOptions(
            aStyleSettings.GetSelectionOptions() | SelectionOptions::ShowFirst);
        aSettings.SetStyleSettings(aStyleSettings);
        m_pWindow->SetSettings(aSettings);
    }

    implAdjustGenericFieldSetting( xModel );

    DbLimitedLengthField::Init( rParent, xCursor );
}

CellControllerRef DbTextField::CreateController() const
{
    return new EditCellController( m_pEdit.get() );
}

void DbTextField::PaintFieldToCell( OutputDevice& _rDev, const tools::Rectangle&&nbsp;_rRect, const Reference< XColumn >& _rxField, const Reference< XNumberFormatter >& _rxFormatter )
{
    if ( m_pPainterImplementation )
        m_pPainterImplementation->SetText( GetFormatText( _rxField, _rxFormatter ) );

    DbLimitedLengthField::PaintFieldToCell( _rDev, _rRect, _rxField, _rxFormatter );
}

OUString DbTextField::GetFormatText(const Reference< XColumn >& _rxField, const Reference< XNumberFormatter >& xFormatter, const Color** /*ppColor*/)
{
    if (!_rxField.is())
        return OUString();

    const css::uno::Reference<css::beans::XPropertySet> xPS(_rxField, UNO_QUERY);
    FormattedColumnValue fmter( xFormatter, xPS );

    try
    {
        return fmter.getFormattedValue();
    }
    catchconst Exception& )
    {
        DBG_UNHANDLED_EXCEPTION("svx");
    }
    return OUString();

}

void DbTextField::UpdateFromField(const Reference< css::sdb::XColumn >& _rxField, const Reference< XNumberFormatter >& xFormatter)
{
    m_pEdit->SetText( GetFormatText( _rxField, xFormatter ) );
    m_pEdit->SetSelection( Selection( SELECTION_MAX, SELECTION_MIN ) );
}

void DbTextField::updateFromModel( Reference< XPropertySet > _rxModel )
{
    OSL_ENSURE( _rxModel.is() && m_pWindow, "DbTextField::updateFromModel: invalid call!" );

    OUString sText;
    _rxModel->getPropertyValue( FM_PROP_TEXT ) >>= sText;

    sal_Int32 nMaxTextLen = m_pEdit->GetMaxTextLen();
    if (nMaxTextLen > 0 && sText.getLength() > nMaxTextLen)
    {
        sal_Int32 nDiff = sText.getLength() - nMaxTextLen;
        sText = sText.replaceAt(sText.getLength() - nDiff,nDiff, u"");
    }

    m_pEdit->SetText( sText );
    m_pEdit->SetSelection( Selection( SELECTION_MAX, SELECTION_MIN ) );
}

bool DbTextField::commitControl()
{
    OUString aText( m_pEdit->GetText( getModelLineEndSetting( m_rColumn.getModel() ) ) );
    // we have to check if the length before we can decide if the value was modified
    sal_Int32 nMaxTextLen = m_pEdit->GetMaxTextLen();
    if (nMaxTextLen > 0)
    {
        OUString sOldValue;
        m_rColumn.getModel()->getPropertyValue( FM_PROP_TEXT ) >>= sOldValue;
        // if the new value didn't change we must set the old long value again
        if ( sOldValue.getLength() > nMaxTextLen && sOldValue.compareTo(aText,nMaxTextLen) == 0 )
            aText = sOldValue;
    }
    m_rColumn.getModel()->setPropertyValue( FM_PROP_TEXT, Any( aText ) );
    return true;
}

void DbTextField::implSetEffectiveMaxTextLen( sal_Int32 _nMaxLen )
{
    if ( m_pEdit )
        m_pEdit->SetMaxTextLen( _nMaxLen );
    if ( m_pPainterImplementation )
        m_pPainterImplementation->SetMaxTextLen( _nMaxLen );
}

DbFormattedField::DbFormattedField(DbGridColumn& _rColumn)
    :DbLimitedLengthField(_rColumn)
{
    // if our model's format key changes we want to propagate the new value to our windows
    doPropertyListening( FM_PROP_FORMATKEY );
}

DbFormattedField::~DbFormattedField()
{
}

void DbFormattedField::Init( BrowserDataWin& rParent, const Reference< XRowSet >& xCursor)
{
    sal_Int16 nAlignment = m_rColumn.SetAlignmentFromModel(-1);

    Reference< css::beans::XPropertySet >  xUnoModel = m_rColumn.getModel();

    auto xEditControl = VclPtr<FormattedControl>::Create(&rParent, false);
    auto xEditPainter = VclPtr<FormattedControl>::Create(&rParent, false);

    weld::EntryFormatter& rControlFormatter = xEditControl->get_formatter();
    weld::EntryFormatter& rPainterFormatter = xEditPainter->get_formatter();

    m_pWindow = xEditControl.get();
    m_pPainter = xEditPainter.get();

    switch (nAlignment)
    {
        case awt::TextAlign::RIGHT:
            xEditControl->get_widget().set_alignment(TxtAlign::Right);
            xEditPainter->get_widget().set_alignment(TxtAlign::Right);
            break;
        case awt::TextAlign::CENTER:
            xEditControl->get_widget().set_alignment(TxtAlign::Center);
            xEditPainter->get_widget().set_alignment(TxtAlign::Center);
            break;
        default:
        {
            // Everything just so that the selection goes from right to left when getting focus
            SelectionOptions eOptions = rControlFormatter.GetEntrySelectionOptions();
            rControlFormatter.SetEntrySelectionOptions(eOptions | SelectionOptions::ShowFirst);
            break;
        }
    }

    implAdjustGenericFieldSetting( xUnoModel );

    rControlFormatter.SetStrictFormat(false);
    rPainterFormatter.SetStrictFormat(false);
        // if one allows any formatting, one cannot make an entry check anyway
        // (the FormattedField does not support that anyway, only derived classes)

    // get the formatter from the uno model
    // (I could theoretically also go via the css::util::NumberFormatter, which the cursor would
    // surely give me. The problem is that I can not really rely on the fact that the two
    // formatters are the same. Clean is the whole thing if I go via the UNO model.)
    sal_Int32 nFormatKey = -1;

    // let's see if the model has one ...
    DBG_ASSERT(::comphelper::hasProperty(FM_PROP_FORMATSSUPPLIER, xUnoModel), "DbFormattedField::Init : invalid UNO model !");
    Any aSupplier( xUnoModel->getPropertyValue(FM_PROP_FORMATSSUPPLIER));
    if (aSupplier.hasValue())
    {
        m_xSupplier.set(aSupplier, css::uno::UNO_QUERY);
        if (m_xSupplier.is())
        {
            // if we take the supplier from the model, then also the key
            Any aFmtKey( xUnoModel->getPropertyValue(FM_PROP_FORMATKEY));
            if (aFmtKey.hasValue())
            {
                DBG_ASSERT(aFmtKey.getValueTypeClass() == TypeClass_LONG, "DbFormattedField::Init : invalid format key property (no sal_Int32) !");
                nFormatKey = ::comphelper::getINT32(aFmtKey);
            }
            else
            {
                SAL_INFO("svx.fmcomp""DbFormattedField::Init : my uno-model has no format-key, but a formats supplier !");
                // the OFormattedModel which we usually are working with ensures that the model has a format key
                // as soon as the form is loaded. Unfortunally this method here is called from within loaded, too.
                // So if our LoadListener is called before the LoadListener of the model, this "else case" is
                // allowed.
                // Of course our property listener for the FormatKey property will notify us if the prop is changed,
                // so this here isn't really bad...
                nFormatKey = 0;
            }
        }
    }

    // No? Maybe the css::form::component::Form behind the cursor?
    if (!m_xSupplier.is())
    {
        if (xCursor.is())
        {   // If we take the formatter from the cursor, then also the key from the field to which we are bound
            m_xSupplier = getNumberFormats(getConnection(xCursor));

            if (m_rColumn.GetField().is())
                nFormatKey = ::comphelper::getINT32(m_rColumn.GetField()->getPropertyValue(FM_PROP_FORMATKEY));
        }
    }

    SvNumberFormatter* pFormatterUsed = nullptr;
    if (m_xSupplier.is())
    {
        SvNumberFormatsSupplierObj* pImplementation = comphelper::getFromUnoTunnel<SvNumberFormatsSupplierObj>(m_xSupplier);
        if (pImplementation)
            pFormatterUsed = pImplementation->GetNumberFormatter();
        else
            // Everything is invalid: the supplier is of the wrong type, then we can not
            // rely on a standard formatter to know the (possibly non-standard) key.
            nFormatKey = -1;
    }

    // a standard formatter ...
    if (pFormatterUsed == nullptr)
    {
        pFormatterUsed = rControlFormatter.StandardFormatter();
        DBG_ASSERT(pFormatterUsed != nullptr, "DbFormattedField::Init : no standard formatter given by the numeric field !");
    }
    // ... and a standard key
    if (nFormatKey == -1)
        nFormatKey = 0;

    rControlFormatter.SetFormatter(pFormatterUsed);
    rPainterFormatter.SetFormatter(pFormatterUsed);

    rControlFormatter.SetFormatKey(nFormatKey);
    rPainterFormatter.SetFormatKey(nFormatKey);

    rControlFormatter.TreatAsNumber(m_rColumn.IsNumeric());
    rPainterFormatter.TreatAsNumber(m_rColumn.IsNumeric());

    // min and max values
    if (m_rColumn.IsNumeric())
    {
        bool bClearMin = true;
        if (::comphelper::hasProperty(FM_PROP_EFFECTIVE_MIN, xUnoModel))
        {
            Any aMin( xUnoModel->getPropertyValue(FM_PROP_EFFECTIVE_MIN));
            if (aMin.getValueTypeClass() != TypeClass_VOID)
            {
                DBG_ASSERT(aMin.getValueTypeClass() == TypeClass_DOUBLE, "DbFormattedField::Init : the model has an invalid min value !");
                double dMin = ::comphelper::getDouble(aMin);
                rControlFormatter.SetMinValue(dMin);
                rPainterFormatter.SetMinValue(dMin);
                bClearMin = false;
            }
        }
        if (bClearMin)
        {
            rControlFormatter.ClearMinValue();
            rPainterFormatter.ClearMinValue();
        }
        bool bClearMax = true;
        if (::comphelper::hasProperty(FM_PROP_EFFECTIVE_MAX, xUnoModel))
        {
            Any aMax(xUnoModel->getPropertyValue(FM_PROP_EFFECTIVE_MAX));
            if (aMax.getValueTypeClass() != TypeClass_VOID)
            {
                DBG_ASSERT(aMax.getValueTypeClass() == TypeClass_DOUBLE, "DbFormattedField::Init : the model has an invalid max value !");
                double dMax = ::comphelper::getDouble(aMax);
                rControlFormatter.SetMaxValue(dMax);
                rPainterFormatter.SetMaxValue(dMax);
                bClearMax = false;
            }
        }
        if (bClearMax)
        {
            rControlFormatter.ClearMaxValue();
            rPainterFormatter.ClearMaxValue();
        }
    }

    // the default value
    Any aDefault( xUnoModel->getPropertyValue(FM_PROP_EFFECTIVE_DEFAULT));
    if (aDefault.hasValue())
    {   // the thing can be a double or a string
        switch (aDefault.getValueTypeClass())
        {
            case TypeClass_DOUBLE:
                if (m_rColumn.IsNumeric())
                {
                    rControlFormatter.SetDefaultValue(::comphelper::getDouble(aDefault));
                    rPainterFormatter.SetDefaultValue(::comphelper::getDouble(aDefault));
                }
                else
                {
                    OUString sConverted;
                    const Color* pDummy;
                    pFormatterUsed->GetOutputString(::comphelper::getDouble(aDefault), 0, sConverted, &pDummy);
                    rControlFormatter.SetDefaultText(sConverted);
                    rPainterFormatter.SetDefaultText(sConverted);
                }
                break;
            case TypeClass_STRING:
            {
                OUString sDefault( ::comphelper::getString(aDefault) );
                if (m_rColumn.IsNumeric())
                {
                    double dVal;
                    sal_uInt32 nTestFormat(0);
                    if (pFormatterUsed->IsNumberFormat(sDefault, nTestFormat, dVal))
                    {
                        rControlFormatter.SetDefaultValue(dVal);
                        rPainterFormatter.SetDefaultValue(dVal);
                    }
                }
                else
                {
                    rControlFormatter.SetDefaultText(sDefault);
                    rPainterFormatter.SetDefaultText(sDefault);
                }
            }
            break;
            default:
                OSL_FAIL( "DbFormattedField::Init: unexpected value type!" );
                break;
        }
    }
    DbLimitedLengthField::Init( rParent, xCursor );
}

CellControllerRef DbFormattedField::CreateController() const
{
    return new ::svt::FormattedFieldCellController(static_cast<FormattedControlBase*>(m_pWindow.get()));
}

void DbFormattedField::_propertyChanged( const PropertyChangeEvent& _rEvent )
{
    if (_rEvent.PropertyName == FM_PROP_FORMATKEY )
    {
        sal_Int32 nNewKey = _rEvent.NewValue.hasValue() ? ::comphelper::getINT32(_rEvent.NewValue) : 0;

        DBG_ASSERT(m_pWindow && m_pPainter, "DbFormattedField::_propertyChanged : where are my windows ?");
        if (m_pWindow)
            static_cast<FormattedControlBase*>(m_pWindow.get())->get_formatter().SetFormatKey(nNewKey);
        if (m_pPainter)
            static_cast<FormattedControlBase*>(m_pPainter.get())->get_formatter().SetFormatKey(nNewKey);
    }
    else
    {
        DbLimitedLengthField::_propertyChanged( _rEvent );
    }
}

OUString DbFormattedField::GetFormatText(const Reference< css::sdb::XColumn >& _rxField, const Reference< XNumberFormatter >& /*xFormatter*/, const Color** ppColor)
{
    // no color specification by default
    if (ppColor != nullptr)
        *ppColor = nullptr;

    // NULL value -> empty text
    if (!_rxField.is())
        return OUString();

    FormattedControlBase* pControl = static_cast<FormattedControlBase*>(m_pPainter.get());
    weld::EntryFormatter& rPainterFormatter = pControl->get_formatter();

    OUString aText;
    try
    {
        if (m_rColumn.IsNumeric())
        {
            // The IsNumeric at the column says nothing about the class of the used format, but
            // about the class of the field bound to the column. So when you bind a FormattedField
            // column to a double field and format it as text, m_rColumn.IsNumeric() returns
            // sal_True. So that simply means that I can query the contents of the variant using
            // getDouble, and then I can leave the rest (the formatting) to the FormattedField.
            double dValue = getValue( _rxField, m_rColumn.GetParent().getNullDate() );
            if (_rxField->wasNull())
                return aText;
            rPainterFormatter.SetValue(dValue);
        }
        else
        {
            // Here I can not work with a double, since the field can not provide it to me.
            // So simply bind the text from the css::util::NumberFormatter to the correct css::form::component::Form.
            aText = _rxField->getString();
            if (_rxField->wasNull())
                return aText;
            rPainterFormatter.SetTextFormatted(aText);
        }
    }
    catchconst Exception& )
    {
        DBG_UNHANDLED_EXCEPTION("svx");
    }

    aText = pControl->get_widget().get_text();
    if (ppColor != nullptr)
        *ppColor = rPainterFormatter.GetLastOutputColor();

    return aText;
}

void DbFormattedField::UpdateFromField(const Reference< css::sdb::XColumn >& _rxField, const Reference< XNumberFormatter >& /*xFormatter*/)
{
    try
    {
        FormattedControlBase* pEditControl = static_cast<FormattedControlBase*>(m_pWindow.get());
        weld::Entry& rEntry = pEditControl->get_widget();
        weld::EntryFormatter& rEditFormatter = pEditControl->get_formatter();

        if (!_rxField.is())
        {
            // NULL value -> empty text
            rEntry.set_text(OUString());
        }
        else if (m_rColumn.IsNumeric())
        {
            // The IsNumeric at the column says nothing about the class of the used format, but
            // about the class of the field bound to the column. So when you bind a FormattedField
            // column to a double field and format it as text, m_rColumn.IsNumeric() returns
            // sal_True. So that simply means that I can query the contents of the variant using
            // getDouble, and then I can leave the rest (the formatting) to the FormattedField.
            double dValue = getValue( _rxField, m_rColumn.GetParent().getNullDate() );
            if (_rxField->wasNull())
                rEntry.set_text(OUString());
            else
                rEditFormatter.SetValue(dValue);
        }
        else
        {
            // Here I can not work with a double, since the field can not provide it to me.
            // So simply bind the text from the css::util::NumberFormatter to the correct css::form::component::Form.
            OUString sText( _rxField->getString());

            rEditFormatter.SetTextFormatted( sText );
            rEntry.select_region(0, -1);
        }
    }
    catchconst Exception& )
    {
        DBG_UNHANDLED_EXCEPTION("svx");
    }
}

void DbFormattedField::updateFromModel( Reference< XPropertySet > _rxModel )
{
    OSL_ENSURE( _rxModel.is() && m_pWindow, "DbFormattedField::updateFromModel: invalid call!" );

    FormattedControlBase* pEditControl = static_cast<FormattedControlBase*>(m_pWindow.get());
    weld::Entry& rEntry = pEditControl->get_widget();
    weld::EntryFormatter& rEditFormatter = pEditControl->get_formatter();

    OUString sText;
    Any aValue = _rxModel->getPropertyValue( FM_PROP_EFFECTIVE_VALUE );
    if ( !aValue.hasValue() || (aValue >>= sText) )
    {
        // our effective value is transferred as string
        rEditFormatter.SetTextFormatted( sText );
        rEntry.select_region(0, -1);
    }
    else
    {
        double dValue = 0;
        aValue >>= dValue;
        rEditFormatter.SetValue(dValue);
    }
}

bool DbFormattedField::commitControl()
{
    Any aNewVal;

    FormattedControlBase* pEditControl = static_cast<FormattedControlBase*>(m_pWindow.get());
    weld::Entry& rEntry = pEditControl->get_widget();
    weld::EntryFormatter& rEditFormatter = pEditControl->get_formatter();

    if (m_rColumn.IsNumeric())
    {
        if (!rEntry.get_text().isEmpty())
            aNewVal <<= rEditFormatter.GetValue();
        // an empty string is passed on as void by default, to start with
    }
    else
        aNewVal <<= rEditFormatter.GetTextValue();

    m_rColumn.getModel()->setPropertyValue(FM_PROP_EFFECTIVE_VALUE, aNewVal);
    return true;
}

DbCheckBox::DbCheckBox( DbGridColumn& _rColumn )
    :DbCellControl( _rColumn )
{
    setAlignedController( false );
}

namespace
{
    void setCheckBoxStyle( vcl::Window* _pWindow, bool bMono )
    {
        AllSettings aSettings = _pWindow->GetSettings();
        StyleSettings aStyleSettings = aSettings.GetStyleSettings();
        if( bMono )
            aStyleSettings.SetOptions( aStyleSettings.GetOptions() | StyleSettingsOptions::Mono );
        else
            aStyleSettings.SetOptions( aStyleSettings.GetOptions() & (~StyleSettingsOptions::Mono) );
        aSettings.SetStyleSettings( aStyleSettings );
        _pWindow->SetSettings( aSettings );
    }
}

void DbCheckBox::Init(BrowserDataWin& rParent, const Reference< XRowSet >& xCursor)
{
    setTransparent( true );

    m_pWindow  = VclPtr<CheckBoxControl>::Create( &rParent );
    m_pPainter = VclPtr<CheckBoxControl>::Create( &rParent );

    m_pWindow->SetPaintTransparent( true );
    m_pPainter->SetPaintTransparent( true );

    m_pPainter->SetBackground();

    try
    {
        Reference< XPropertySet > xModel( m_rColumn.getModel(), UNO_SET_THROW );

        sal_Int16 nStyle = awt::VisualEffect::LOOK3D;
        OSL_VERIFY( xModel->getPropertyValue( FM_PROP_VISUALEFFECT ) >>= nStyle );

        setCheckBoxStyle( m_pWindow, nStyle == awt::VisualEffect::FLAT );
        setCheckBoxStyle( m_pPainter, nStyle == awt::VisualEffect::FLAT );

        bool bTristate = true;
        OSL_VERIFY( xModel->getPropertyValue( FM_PROP_TRISTATE ) >>= bTristate );
        static_cast< CheckBoxControl* >( m_pWindow.get() )->EnableTriState( bTristate );
        static_cast< CheckBoxControl* >( m_pPainter.get() )->EnableTriState( bTristate );
    }
    catchconst Exception& )
    {
        DBG_UNHANDLED_EXCEPTION("svx");
    }

    DbCellControl::Init( rParent, xCursor );
}

CellControllerRef DbCheckBox::CreateController() const
{
    return new CheckBoxCellController(static_cast<CheckBoxControl*>(m_pWindow.get()));
}

static void lcl_setCheckBoxState(   const Reference< css::sdb::XColumn >& _rxField,
                        CheckBoxControl* _pCheckBoxControl )
{
    TriState eState = TRISTATE_INDET;
    if (_rxField.is())
    {
        try
        {
            bool bValue = _rxField->getBoolean();
            if (!_rxField->wasNull())
                eState = bValue ? TRISTATE_TRUE : TRISTATE_FALSE;
        }
        catchconst Exception& )
        {
            DBG_UNHANDLED_EXCEPTION("svx");
        }
    }
    _pCheckBoxControl->SetState(eState);
}

void DbCheckBox::UpdateFromField(const Reference< css::sdb::XColumn >& _rxField, const Reference< XNumberFormatter >& /*xFormatter*/)
{
    lcl_setCheckBoxState( _rxField, static_cast<CheckBoxControl*>(m_pWindow.get()) );
}

void DbCheckBox::PaintFieldToCell(OutputDevice& rDev, const tools::Rectangle& ;rRect,
                          const Reference< css::sdb::XColumn >& _rxField,
                          const Reference< XNumberFormatter >& xFormatter)
{
    CheckBoxControl* pControl = static_cast<CheckBoxControl*>(m_pPainter.get());
    lcl_setCheckBoxState( _rxField, pControl );

    Size aBoxSize;

    switch (rDev.GetOutDevType())
    {
        case OUTDEV_WINDOW:
        case OUTDEV_VIRDEV:
            aBoxSize = pControl->GetBox().get_preferred_size();
            break;
        case OUTDEV_PRINTER:
        case OUTDEV_PDF:
        {
            auto nSize = std::min(rRect.GetWidth(), rRect.GetHeight());
            aBoxSize = Size(nSize, nSize);
            break;
        }
    }

    tools::Rectangle aRect(Point(rRect.Left() + ((rRect.GetWidth() - aBoxSize.Width()) / 2),
                                 rRect.Top() + ((rRect.GetHeight() - aBoxSize.Height()) / 2)),
                           aBoxSize);

    DbCellControl::PaintFieldToCell(rDev, aRect, _rxField, xFormatter);
}

void DbCheckBox::PaintCell(OutputDevice& rDev, const tools::Rectangle& rRect)
{
    switch (rDev.GetOutDevType())
    {
        case OUTDEV_WINDOW:
        case OUTDEV_VIRDEV:
            DbCellControl::PaintCell(rDev, rRect);
            break;
        case OUTDEV_PRINTER:
        case OUTDEV_PDF:
        {
            TriState eState = static_cast<CheckBoxControl*>(m_pWindow.get())->GetState();

            MapMode aResMapMode(MapUnit::Map100thMM);
            Size aImageSize = rDev.LogicToPixel(Size(300, 300), aResMapMode);
            Size aBrd1Size = rDev.LogicToPixel(Size(20, 20), aResMapMode);
            Size aBrd2Size = rDev.LogicToPixel(Size(30, 30), aResMapMode);
            int nCheckWidth = rDev.LogicToPixel(Size(20, 20), aResMapMode).Width();

            tools::Rectangle aStateRect;
            aStateRect.SetLeft(rRect.Left() + ((rRect.GetWidth() - aImageSize.Width()) / 2));
            aStateRect.SetTop(rRect.Top() + ((rRect.GetHeight() - aImageSize.Height()) / 2));
            aStateRect.SetRight(aStateRect.Left() + aImageSize.Width() - 1);
            aStateRect.SetBottom(aStateRect.Top() + aImageSize.Height() - 1);

            rDev.Push();
            rDev.SetMapMode();

            rDev.SetLineColor();
            rDev.SetFillColor(COL_BLACK);
            rDev.DrawRect(aStateRect);
            aStateRect.AdjustLeft(aBrd1Size.Width());
            aStateRect.AdjustTop(aBrd1Size.Height());
            aStateRect.AdjustRight(-aBrd1Size.Width());
            aStateRect.AdjustBottom(-aBrd1Size.Height());
            if (eState == TRISTATE_INDET)
                rDev.SetFillColor(COL_LIGHTGRAY);
            else
                rDev.SetFillColor(COL_WHITE);
            rDev.DrawRect(aStateRect);

            if (eState == TRISTATE_TRUE)
            {
                aStateRect.AdjustLeft(aBrd2Size.Width());
                aStateRect.AdjustTop(aBrd2Size.Height());
                aStateRect.AdjustRight(-aBrd2Size.Width());
                aStateRect.AdjustBottom(-aBrd2Size.Height());
                Point aPos11(aStateRect.TopLeft());
                Point aPos12(aStateRect.BottomRight());
                Point aPos21(aStateRect.TopRight());
                Point aPos22(aStateRect.BottomLeft());
                Point aTempPos11(aPos11);
                Point aTempPos12(aPos12);
                Point aTempPos21(aPos21);
                Point aTempPos22(aPos22);
                rDev.SetLineColor(COL_BLACK);
                int nDX = 0;
                for (int i = 0; i < nCheckWidth; i++)
                {
                    if ( !(i % 2) )
                    {
                        aTempPos11.setX(aPos11.X() + nDX);
                        aTempPos12.setX(aPos12.X() + nDX);
                        aTempPos21.setX(aPos21.X() + nDX);
                        aTempPos22.setX(aPos22.X() + nDX);
                    }
                    else
                    {
                        nDX++;
                        aTempPos11.setX(aPos11.X() - nDX);
                        aTempPos12.setX(aPos12.X() - nDX);
                        aTempPos21.setX(aPos21.X() - nDX);
                        aTempPos22.setX(aPos22.X() - nDX);
                    }
                    rDev.DrawLine(aTempPos11, aTempPos12);
                    rDev.DrawLine(aTempPos21, aTempPos22);
                }
            }

            rDev.Pop();
            break;
        }
    }
}

void DbCheckBox::updateFromModel( Reference< XPropertySet > _rxModel )
{
    OSL_ENSURE( _rxModel.is() && m_pWindow, "DbCheckBox::updateFromModel: invalid call!" );

    sal_Int16 nState = TRISTATE_INDET;
    _rxModel->getPropertyValue( FM_PROP_STATE ) >>= nState;
    static_cast< CheckBoxControl* >( m_pWindow.get() )->SetState( static_cast< TriState >( nState ) );
}

bool DbCheckBox::commitControl()
{
    m_rColumn.getModel()->setPropertyValue( FM_PROP_STATE,
                    Any( static_cast<sal_Int16>( static_cast< CheckBoxControl* >( m_pWindow.get() )->GetState() ) ) );
    return true;
}

OUString DbCheckBox::GetFormatText(const Reference< XColumn >& /*_rxField*/, const Reference< XNumberFormatter >& /*xFormatter*/, const Color** /*ppColor*/)
{
    return OUString();
}

DbPatternField::DbPatternField( DbGridColumn& _rColumn, const Reference<XComponentContext>& _rContext )
    :DbCellControl( _rColumn )
    ,m_xContext( _rContext )
{
    doPropertyListening( FM_PROP_LITERALMASK );
    doPropertyListening( FM_PROP_EDITMASK );
    doPropertyListening( FM_PROP_STRICTFORMAT );
}

void DbPatternField::implAdjustGenericFieldSetting( const Reference< XPropertySet >& ;_rxModel )
{
    DBG_ASSERT( m_pWindow, "DbPatternField::implAdjustGenericFieldSetting: not to be called without window!" );
    DBG_ASSERT( _rxModel.is(), "DbPatternField::implAdjustGenericFieldSetting: invalid model!" );
    if ( !m_pWindow || !_rxModel.is() )
        return;

    OUString aLitMask;
    OUString aEditMask;
    bool bStrict = false;

    _rxModel->getPropertyValue( FM_PROP_LITERALMASK ) >>= aLitMask;
    _rxModel->getPropertyValue( FM_PROP_EDITMASK ) >>= aEditMask;
    _rxModel->getPropertyValue( FM_PROP_STRICTFORMAT ) >>= bStrict;

    OString aAsciiEditMask(OUStringToOString(aEditMask, RTL_TEXTENCODING_ASCII_US));

    weld::PatternFormatter& rEditFormatter = static_cast<PatternControl*>(m_pWindow.get())->get_formatter();
    rEditFormatter.SetMask(aAsciiEditMask, aLitMask);
    rEditFormatter.SetStrictFormat(bStrict);

    weld::PatternFormatter& rPaintFormatter = static_cast<PatternControl*>(m_pPainter.get())->get_formatter();
    rPaintFormatter.SetMask(aAsciiEditMask, aLitMask);
    rPaintFormatter.SetStrictFormat(bStrict);
}

void DbPatternField::Init(BrowserDataWin& rParent, const Reference< XRowSet >& xCursor)
{
    m_rColumn.SetAlignmentFromModel(-1);

    m_pWindow = VclPtr<PatternControl>::Create(&rParent);
    m_pPainter= VclPtr<PatternControl>::Create(&rParent);

    Reference< XPropertySet >   xModel( m_rColumn.getModel() );
    implAdjustGenericFieldSetting( xModel );

    DbCellControl::Init( rParent, xCursor );
}

CellControllerRef DbPatternField::CreateController() const
{
    return new EditCellController(static_cast<PatternControl*>(m_pWindow.get()));
}

OUString DbPatternField::impl_formatText( const OUString& _rText )
{
    weld::PatternFormatter& rPaintFormatter = static_cast<PatternControl*>(m_pPainter.get())->get_formatter();
    rPaintFormatter.get_widget().set_text(_rText);
    rPaintFormatter.ReformatAll();
    return rPaintFormatter.get_widget().get_text();
}

OUString DbPatternField::GetFormatText(const Reference< css::sdb::XColumn >& _rxField, const Reference< XNumberFormatter >& /*xFormatter*/, const Color** /*ppColor*/)
{
    bool bIsForPaint = _rxField != m_rColumn.GetField();
    ::std::unique_ptr< FormattedColumnValue >& rpFormatter = bIsForPaint ? m_pPaintFormatter : m_pValueFormatter;

    if (!rpFormatter)
    {
        rpFormatter = std::make_unique< FormattedColumnValue> (
            m_xContext, getCursor(), Reference< XPropertySet >( _rxField, UNO_QUERY ) );
        OSL_ENSURE(rpFormatter, "DbPatternField::Init: no value formatter!");
    }
    else
        OSL_ENSURE( rpFormatter->getColumn() == _rxField, "DbPatternField::GetFormatText: my value formatter is working for another field ...!" );
        // re-creating the value formatter here every time would be quite expensive ...

    OUString sText;
    if (rpFormatter)
        sText = rpFormatter->getFormattedValue();

    return impl_formatText( sText );
}

void DbPatternField::UpdateFromField( const Reference< XColumn >& _rxField, const Reference< XNumberFormatter >& _rxFormatter )
{
    weld::Entry& rEntry = static_cast<PatternControl*>(m_pWindow.get())->get_widget();
    rEntry.set_text(GetFormatText(_rxField, _rxFormatter));
    rEntry.select_region(-1, 0);
}

void DbPatternField::updateFromModel( Reference< XPropertySet > _rxModel )
{
    OSL_ENSURE( _rxModel.is() && m_pWindow, "DbPatternField::updateFromModel: invalid call!" );

    OUString sText;
    _rxModel->getPropertyValue( FM_PROP_TEXT ) >>= sText;

    weld::Entry& rEntry = static_cast<PatternControl*>(m_pWindow.get())->get_widget();
    rEntry.set_text(impl_formatText(sText));
    rEntry.select_region(-1, 0);
}

bool DbPatternField::commitControl()
{
    weld::Entry& rEntry = static_cast<PatternControl*>(m_pWindow.get())->get_widget();
    m_rColumn.getModel()->setPropertyValue(FM_PROP_TEXT, Any(rEntry.get_text()));
    return true;
}

DbSpinField::DbSpinField( DbGridColumn& _rColumn, sal_Int16 _nStandardAlign )
    :DbCellControl( _rColumn )
    ,m_nStandardAlign( _nStandardAlign )
{
}

void DbSpinField::Init(BrowserDataWin& _rParent, const Reference< XRowSet >& _rxCursor)
{
    m_rColumn.SetAlignmentFromModel( m_nStandardAlign );

    Reference< XPropertySet > xModel( m_rColumn.getModel() );

    // determine if we need a spinbutton version
    bool bSpinButton(false);
    if ( ::comphelper::getBOOL( xModel->getPropertyValue( FM_PROP_SPIN ) ) )
        bSpinButton = true;
    // create the fields
    m_pWindow = createField( &_rParent, bSpinButton, xModel );
    m_pPainter = createField( &_rParent, bSpinButton, xModel );

    // adjust all other settings which depend on the property values
    implAdjustGenericFieldSetting( xModel );

    // call the base class
    DbCellControl::Init( _rParent, _rxCursor );
}

CellControllerRef DbSpinField::CreateController() const
{
    return new ::svt::FormattedFieldCellController(static_cast<FormattedControlBase*>(m_pWindow.get()));
}

DbNumericField::DbNumericField( DbGridColumn& _rColumn )
    :DbSpinField( _rColumn )
{
    doPropertyListening( FM_PROP_DECIMAL_ACCURACY );
    doPropertyListening( FM_PROP_VALUEMIN );
    doPropertyListening( FM_PROP_VALUEMAX );
    doPropertyListening( FM_PROP_VALUESTEP );
    doPropertyListening( FM_PROP_STRICTFORMAT );
    doPropertyListening( FM_PROP_SHOWTHOUSANDSEP );
}

void DbNumericField::implAdjustGenericFieldSetting( const Reference< XPropertySet >& ;_rxModel )
{
    DBG_ASSERT( m_pWindow, "DbNumericField::implAdjustGenericFieldSetting: not to be called without window!" );
    DBG_ASSERT( _rxModel.is(), "DbNumericField::implAdjustGenericFieldSetting: invalid model!" );
    if ( !m_pWindow || !_rxModel.is() )
        return;

    sal_Int32   nMin        = static_cast<sal_Int32>(getDouble( _rxModel->getPropertyValue( FM_PROP_VALUEMIN ) ));
    sal_Int32   nMax        = static_cast<sal_Int32>(getDouble( _rxModel->getPropertyValue( FM_PROP_VALUEMAX ) ));
    sal_Int32   nStep       = static_cast<sal_Int32>(getDouble( _rxModel->getPropertyValue( FM_PROP_VALUESTEP ) ));
    bool    bStrict     = getBOOL( _rxModel->getPropertyValue( FM_PROP_STRICTFORMAT ) );
    sal_Int16   nScale      = getINT16( _rxModel->getPropertyValue( FM_PROP_DECIMAL_ACCURACY ) );
    bool    bThousand   = getBOOL( _rxModel->getPropertyValue( FM_PROP_SHOWTHOUSANDSEP ) );

    Formatter& rEditFormatter = static_cast<FormattedControlBase*>(m_pWindow.get())->get_formatter();
    rEditFormatter.SetMinValue(nMin);
    rEditFormatter.SetMaxValue(nMax);
    rEditFormatter.SetSpinSize(nStep);
    rEditFormatter.SetStrictFormat(bStrict);

    Formatter& rPaintFormatter = static_cast<FormattedControlBase*>(m_pPainter.get())->get_formatter();
    rPaintFormatter.SetMinValue(nMin);
    rPaintFormatter.SetMaxValue(nMax);
    rPaintFormatter.SetStrictFormat(bStrict);

    // give a formatter to the field and the painter;
    // test first if I can get from the service behind a connection
    Reference< css::util::XNumberFormatsSupplier >  xSupplier;
    Reference< XRowSet > xForm;
    if ( m_rColumn.GetParent().getDataSource() )
        xForm.set( Reference< XInterface >(*m_rColumn.GetParent().getDataSource()), UNO_QUERY );
    if ( xForm.is() )
        xSupplier = getNumberFormats( getConnection( xForm ), true );
    SvNumberFormatter* pFormatterUsed = nullptr;
    if ( xSupplier.is() )
    {
        SvNumberFormatsSupplierObj* pImplementation = comphelper::getFromUnoTunnel<SvNumberFormatsSupplierObj>( xSupplier );
        pFormatterUsed = pImplementation ? pImplementation->GetNumberFormatter() : nullptr;
    }
    if ( nullptr == pFormatterUsed )
    {   // the cursor didn't lead to success -> standard
        pFormatterUsed = rEditFormatter.StandardFormatter();
        DBG_ASSERT( pFormatterUsed != nullptr, "DbNumericField::implAdjustGenericFieldSetting: no standard formatter given by the numeric field !" );
    }
    rEditFormatter.SetFormatter( pFormatterUsed );
    rPaintFormatter.SetFormatter( pFormatterUsed );

    // and then generate a format which has the desired length after the decimal point, etc.
    LanguageType aAppLanguage = Application::GetSettings().GetUILanguageTag().getLanguageType();
    OUString sFormatString = pFormatterUsed->GenerateFormat(0, aAppLanguage, bThousand, false, nScale);

    rEditFormatter.SetFormat( sFormatString, aAppLanguage );
    rPaintFormatter.SetFormat( sFormatString, aAppLanguage );
}

VclPtr<svt::ControlBase> DbNumericField::createField(BrowserDataWin* pParent, bool bSpinButton, const Reference<XPropertySet>& /*rxModel*/)
{
    return VclPtr<DoubleNumericControl>::Create(pParent, bSpinButton);
}

namespace
{
    OUString lcl_setFormattedNumeric_nothrow( FormattedControlBase& _rField, const DbCellControl& _rControl,
        const Reference< XColumn >& _rxField, const Reference< XNumberFormatter >& _rxFormatter )
    {
        OUString sValue;
        if ( _rxField.is() )
        {
            try
            {
                double fValue = _rControl.GetValue( _rxField, _rxFormatter );
                if ( !_rxField->wasNull() )
                {
                    _rField.get_formatter().SetValue(fValue);
                    sValue = _rField.get_widget().get_text();
                }
            }
            catchconst Exception& )
            {
                DBG_UNHANDLED_EXCEPTION("svx");
            }
        }
        return sValue;
    }
}

OUString DbNumericField::GetFormatText(const Reference< css::sdb::XColumn >& _rxField, const Reference< css::util::XNumberFormatter >& _rxFormatter, const Color** /*ppColor*/)
{
    return lcl_setFormattedNumeric_nothrow(dynamic_cast<FormattedControlBase&>(*m_pPainter), *this, _rxField, _rxFormatter);
}

void DbNumericField::UpdateFromField(const Reference< css::sdb::XColumn >& _rxFieldconst Reference< css::util::XNumberFormatter >& _rxFormatter)
{
    lcl_setFormattedNumeric_nothrow(dynamic_cast<FormattedControlBase&>(*m_pWindow), *this, _rxField, _rxFormatter);
}

void DbNumericField::updateFromModel( Reference< XPropertySet > _rxModel )
{
    OSL_ENSURE( _rxModel.is() && m_pWindow, "DbNumericField::updateFromModel: invalid call!" );

    FormattedControlBase* pControl = static_cast<FormattedControlBase*>(m_pWindow.get());
    Formatter& rFormatter = pControl->get_formatter();

    double dValue = 0;
    if ( _rxModel->getPropertyValue( FM_PROP_VALUE ) >>= dValue )
        rFormatter.SetValue(dValue);
    else
    {
        pControl->get_widget().set_text(OUString());
        rFormatter.InvalidateValueState();
    }
}

bool DbNumericField::commitControl()
{
    FormattedControlBase* pControl = static_cast<FormattedControlBase*>(m_pWindow.get());
    OUString aText(pControl->get_widget().get_text());
    Any aVal;

    if (!aText.isEmpty())   // not empty
    {
        Formatter& rFormatter = pControl->get_formatter();
        double fValue = rFormatter.GetValue();
        aVal <<= fValue;
    }
    m_rColumn.getModel()->setPropertyValue(FM_PROP_VALUE, aVal);
    return true;
}

DbCurrencyField::DbCurrencyField(DbGridColumn& _rColumn)
    :DbSpinField( _rColumn )
{
    doPropertyListening( FM_PROP_DECIMAL_ACCURACY );
    doPropertyListening( FM_PROP_VALUEMIN );
    doPropertyListening( FM_PROP_VALUEMAX );
    doPropertyListening( FM_PROP_VALUESTEP );
    doPropertyListening( FM_PROP_STRICTFORMAT );
    doPropertyListening( FM_PROP_SHOWTHOUSANDSEP );
    doPropertyListening( FM_PROP_CURRENCYSYMBOL );
}

void DbCurrencyField::implAdjustGenericFieldSetting( const Reference< XPropertySet >&&nbsp;_rxModel )
{
    DBG_ASSERT( m_pWindow, "DbCurrencyField::implAdjustGenericFieldSetting: not to be called without window!" );
    DBG_ASSERT( _rxModel.is(), "DbCurrencyField::implAdjustGenericFieldSetting: invalid model!" );
    if ( !m_pWindow || !_rxModel.is() )
        return;

    sal_Int16 nScale        = getINT16( _rxModel->getPropertyValue( FM_PROP_DECIMAL_ACCURACY ) );
    double  nMin            = getDouble( _rxModel->getPropertyValue( FM_PROP_VALUEMIN ) );
    double  nMax            = getDouble( _rxModel->getPropertyValue( FM_PROP_VALUEMAX ) );
    double  nStep           = getDouble( _rxModel->getPropertyValue( FM_PROP_VALUESTEP ) );
    bool    bStrict     = getBOOL( _rxModel->getPropertyValue( FM_PROP_STRICTFORMAT ) );
    bool    bThousand   = getBOOL( _rxModel->getPropertyValue( FM_PROP_SHOWTHOUSANDSEP ) );
    OUString aStr( getString( _rxModel->getPropertyValue(FM_PROP_CURRENCYSYMBOL ) ) );

    Formatter& rEditFormatter = static_cast<FormattedControlBase*>(m_pWindow.get())->get_formatter();
    rEditFormatter.SetDecimalDigits(nScale);
    rEditFormatter.SetMinValue(nMin);
    rEditFormatter.SetMaxValue(nMax);
    rEditFormatter.SetSpinSize(nStep);
    rEditFormatter.SetStrictFormat(bStrict);
    weld::LongCurrencyFormatter& rCurrencyEditFormatter = static_cast<weld::LongCurrencyFormatter&>(rEditFormatter);
    rCurrencyEditFormatter.SetUseThousandSep(bThousand);
    rCurrencyEditFormatter.SetCurrencySymbol(aStr);

    Formatter& rPaintFormatter = static_cast<FormattedControlBase*>(m_pPainter.get())->get_formatter();
    rPaintFormatter.SetDecimalDigits(nScale);
    rPaintFormatter.SetMinValue(nMin);
    rPaintFormatter.SetMaxValue(nMax);
    rPaintFormatter.SetStrictFormat(bStrict);
    weld::LongCurrencyFormatter& rPaintCurrencyFormatter = static_cast<weld::LongCurrencyFormatter&>(rPaintFormatter);
    rPaintCurrencyFormatter.SetUseThousandSep(bThousand);
    rPaintCurrencyFormatter.SetCurrencySymbol(aStr);
}

VclPtr<svt::ControlBase> DbCurrencyField::createField(BrowserDataWin* pParent, bool bSpinButton, const Reference< XPropertySet >& /*rxModel*/)
{
    return VclPtr<LongCurrencyControl>::Create(pParent, bSpinButton);
}

namespace
{
    OUString lcl_setFormattedCurrency_nothrow( FormattedControlBase& _rField, const DbCurrencyField& _rControl,
        const Reference< XColumn >& _rxField, const Reference< XNumberFormatter >& _rxFormatter )
    {
        OUString sValue;
        if ( _rxField.is() )
        {
            try
            {
                double fValue = _rControl.GetValue( _rxField, _rxFormatter );
                if ( !_rxField->wasNull() )
                {
                    _rField.get_formatter().SetValue(fValue);
                    sValue = _rField.get_widget().get_text();
                }
            }
            catchconst Exception& )
            {
                DBG_UNHANDLED_EXCEPTION("svx");
            }
        }
        return sValue;
    }
}

OUString DbCurrencyField::GetFormatText(const Reference< css::sdb::XColumn >& _rxField, const Reference< css::util::XNumberFormatter >& _rxFormatter, const Color** /*ppColor*/)
{
    return lcl_setFormattedCurrency_nothrow(dynamic_cast<FormattedControlBase&>(*m_pPainter), *this, _rxField, _rxFormatter);
}

void DbCurrencyField::UpdateFromField(const Reference< css::sdb::XColumn >& _rxField, const Reference< css::util::XNumberFormatter >& _rxFormatter)
{
    lcl_setFormattedCurrency_nothrow(dynamic_cast<FormattedControlBase&>(*m_pWindow), *this, _rxField, _rxFormatter);
}

void DbCurrencyField::updateFromModel( Reference< XPropertySet > _rxModel )
{
    OSL_ENSURE( _rxModel.is() && m_pWindow, "DbCurrencyField::updateFromModel: invalid call!" );

    FormattedControlBase* pControl = static_cast<FormattedControlBase*>(m_pWindow.get());
    Formatter& rFormatter = pControl->get_formatter();

    double dValue = 0;
    if ( _rxModel->getPropertyValue( FM_PROP_VALUE ) >>= dValue )
        rFormatter.SetValue(dValue);
    else
    {
        pControl->get_widget().set_text(OUString());
        rFormatter.InvalidateValueState();
    }
}

bool DbCurrencyField::commitControl()
{
    FormattedControlBase* pControl = static_cast<FormattedControlBase*>(m_pWindow.get());
    OUString aText(pControl->get_widget().get_text());
    Any aVal;

    if (!aText.isEmpty())   // not empty
    {
        Formatter& rFormatter = pControl->get_formatter();
        double fValue = rFormatter.GetValue();
        aVal <<= fValue;
    }
    m_rColumn.getModel()->setPropertyValue(FM_PROP_VALUE, aVal);
    return true;
}

DbDateField::DbDateField( DbGridColumn& _rColumn )
    :DbSpinField( _rColumn )
{
    doPropertyListening( FM_PROP_DATEFORMAT );
    doPropertyListening( FM_PROP_DATEMIN );
    doPropertyListening( FM_PROP_DATEMAX );
    doPropertyListening( FM_PROP_STRICTFORMAT );
    doPropertyListening( FM_PROP_DATE_SHOW_CENTURY );
}

VclPtr<svt::ControlBase> DbDateField::createField(BrowserDataWin* pParent, bool bSpinButton, const Reference< XPropertySet >& rxModel)
{
    // check if there is a DropDown property set to TRUE
    bool bDropDown =    !hasProperty( FM_PROP_DROPDOWN, rxModel )
                        ||  getBOOL( rxModel->getPropertyValue( FM_PROP_DROPDOWN ) );
    // given the apparent inability to set a custom up/down action for a gtk
    // spinbutton to have different up/down dates depending on the zone the
    // mouse is in, show the dropdown calendar for both the spin or dropdown case
    return VclPtr<DateControl>::Create(pParent, bSpinButton || bDropDown);
}

void DbDateField::implAdjustGenericFieldSetting( const Reference< XPropertySet >& _rxModel )
{
    DBG_ASSERT( m_pWindow, "DbDateField::implAdjustGenericFieldSetting: not to be called without window!" );
    DBG_ASSERT( _rxModel.is(), "DbDateField::implAdjustGenericFieldSetting: invalid model!" );
    if ( !m_pWindow || !_rxModel.is() )
        return;

    sal_Int16   nFormat     = getINT16( _rxModel->getPropertyValue( FM_PROP_DATEFORMAT ) );
    util::Date  aMin;
    OSL_VERIFY( _rxModel->getPropertyValue( FM_PROP_DATEMIN ) >>= aMin );
    util::Date  aMax;
    OSL_VERIFY( _rxModel->getPropertyValue( FM_PROP_DATEMAX ) >>= aMax );
    bool    bStrict     = getBOOL( _rxModel->getPropertyValue( FM_PROP_STRICTFORMAT ) );

    FormattedControlBase* pControl = static_cast<FormattedControlBase*>(m_pWindow.get());
    weld::DateFormatter& rControlFormatter = static_cast<weld::DateFormatter&>(pControl->get_formatter());

    FormattedControlBase* pPainter = static_cast<FormattedControlBase*>(m_pPainter.get());
    weld::DateFormatter& rPainterFormatter = static_cast<weld::DateFormatter&>(pPainter->get_formatter());

    Any  aCentury = _rxModel->getPropertyValue( FM_PROP_DATE_SHOW_CENTURY );
    if ( aCentury.getValueTypeClass() != TypeClass_VOID )
    {
        bool bShowDateCentury = getBOOL( aCentury );

        rControlFormatter.SetShowDateCentury(bShowDateCentury);
        rPainterFormatter.SetShowDateCentury(bShowDateCentury);
    }

    rControlFormatter.SetExtDateFormat( static_cast<ExtDateFieldFormat>(nFormat) );
    rControlFormatter.SetMin( ::Date(aMin) );
    rControlFormatter.SetMax( ::Date(aMax) );
    rControlFormatter.SetStrictFormat( bStrict );
    rControlFormatter.EnableEmptyField( true );

    rPainterFormatter.SetExtDateFormat( static_cast<ExtDateFieldFormat>(nFormat) );
    rPainterFormatter.SetMin( ::Date(aMin) );
    rPainterFormatter.SetMax( ::Date(aMax) );
    rPainterFormatter.SetStrictFormat( bStrict );
    rPainterFormatter.EnableEmptyField( true );
}

namespace
{
    OUString lcl_setFormattedDate_nothrow(DateControl& _rField, const Reference<XColumn>& _rxField)
    {
        OUString sDate;
        if ( _rxField.is() )
        {
            try
            {
                css::util::Date aValue = _rxField->getDate();
                if (!_rxField->wasNull())
                {
                    _rField.SetDate(::Date(aValue.Day, aValue.Month, aValue.Year));
                    sDate = _rField.get_widget().get_text();
                }
            }
            catchconst Exception& )
            {
                DBG_UNHANDLED_EXCEPTION("svx");
            }
        }
        return sDate;
    }
}

OUString DbDateField::GetFormatText(const Reference< css::sdb::XColumn >& _rxField, const Reference< css::util::XNumberFormatter >& /*xFormatter*/, const Color** /*ppColor*/)
{
     return lcl_setFormattedDate_nothrow(*static_cast<DateControl*>(m_pPainter.get()), _rxField);
}

void DbDateField::UpdateFromField(const Reference< css::sdb::XColumn >& _rxField, const Reference< XNumberFormatter >& /*xFormatter*/)
{
    lcl_setFormattedDate_nothrow(*static_cast<DateControl*>(m_pWindow.get()), _rxField);
}

void DbDateField::updateFromModel( Reference< XPropertySet > _rxModel )
{
    OSL_ENSURE( _rxModel.is() && m_pWindow, "DbDateField::updateFromModel: invalid call!" );

    DateControl* pControl = static_cast<DateControl*>(m_pWindow.get());

    util::Date aDate;
    if ( _rxModel->getPropertyValue( FM_PROP_DATE ) >>= aDate )
        pControl->SetDate(::Date(aDate));
    else
        pControl->get_widget().set_text(OUString());
}

bool DbDateField::commitControl()
{
    FormattedControlBase* pControl = static_cast<FormattedControlBase*>(m_pWindow.get());
    OUString aText(pControl->get_widget().get_text());
    Any aVal;

    if (!aText.isEmpty())   // not empty
    {
        weld::DateFormatter& rControlFormatter = static_cast<weld::DateFormatter&>(pControl->get_formatter());
        aVal <<= rControlFormatter.GetDate().GetUNODate();
    }

    m_rColumn.getModel()->setPropertyValue(FM_PROP_DATE, aVal);
    return true;
}

DbTimeField::DbTimeField( DbGridColumn& _rColumn )
    :DbSpinField( _rColumn, css::awt::TextAlign::LEFT )
{
    doPropertyListening( FM_PROP_TIMEFORMAT );
    doPropertyListening( FM_PROP_TIMEMIN );
    doPropertyListening( FM_PROP_TIMEMAX );
    doPropertyListening( FM_PROP_STRICTFORMAT );
}

VclPtr<svt::ControlBase> DbTimeField::createField(BrowserDataWin* pParent, bool bSpinButton, const Reference< XPropertySet >& /*rxModel*/ )
{
    return VclPtr<TimeControl>::Create(pParent, bSpinButton);
}

void DbTimeField::implAdjustGenericFieldSetting( const Reference< XPropertySet >& _rxModel )
{
    DBG_ASSERT( m_pWindow, "DbTimeField::implAdjustGenericFieldSetting: not to be called without window!" );
    DBG_ASSERT( _rxModel.is(), "DbTimeField::implAdjustGenericFieldSetting: invalid model!" );
    if ( !m_pWindow || !_rxModel.is() )
        return;

    sal_Int16   nFormat     = getINT16( _rxModel->getPropertyValue( FM_PROP_TIMEFORMAT ) );
    util::Time  aMin;
    OSL_VERIFY( _rxModel->getPropertyValue( FM_PROP_TIMEMIN ) >>= aMin );
    util::Time  aMax;
    OSL_VERIFY( _rxModel->getPropertyValue( FM_PROP_TIMEMAX ) >>= aMax );
    bool    bStrict     = getBOOL( _rxModel->getPropertyValue( FM_PROP_STRICTFORMAT ) );

    FormattedControlBase* pControl = static_cast<FormattedControlBase*>(m_pWindow.get());
    weld::TimeFormatter& rControlFormatter = static_cast<weld::TimeFormatter&>(pControl->get_formatter());

    rControlFormatter.SetExtFormat(static_cast<ExtTimeFieldFormat>(nFormat));
    rControlFormatter.SetMin(tools::Time(aMin));
    rControlFormatter.SetMax(tools::Time(aMax));
    rControlFormatter.SetStrictFormat(bStrict);
    rControlFormatter.EnableEmptyField(true);

    FormattedControlBase* pPainter = static_cast<FormattedControlBase*>(m_pPainter.get());
    weld::TimeFormatter& rPainterFormatter = static_cast<weld::TimeFormatter&>(pPainter->get_formatter());

    rPainterFormatter.SetExtFormat(static_cast<ExtTimeFieldFormat>(nFormat));
    rPainterFormatter.SetMin(tools::Time(aMin));
    rPainterFormatter.SetMax(tools::Time(aMax));
    rPainterFormatter.SetStrictFormat(bStrict);
    rPainterFormatter.EnableEmptyField(true);
}

namespace
{
    OUString lcl_setFormattedTime_nothrow(TimeControl& _rField, const Reference<XColumn>& _rxField)
    {
        OUString sTime;
        if ( _rxField.is() )
        {
            try
            {
                css::util::Time aValue = _rxField->getTime();
                if (!_rxField->wasNull())
                {
                    static_cast<weld::TimeFormatter&>(_rField.get_formatter()).SetTime( ::tools::Time( aValue ) );
                    sTime = _rField.get_widget().get_text();
                }
            }
            catchconst Exception& )
            {
                DBG_UNHANDLED_EXCEPTION("svx");
            }
        }
        return sTime;
    }
}

OUString DbTimeField::GetFormatText(const Reference< css::sdb::XColumn >& _rxField, const Reference< css::util::XNumberFormatter >& /*xFormatter*/, const Color** /*ppColor*/)
{
    return lcl_setFormattedTime_nothrow(*static_cast<TimeControl*>(m_pPainter.get()), _rxField);
}

void DbTimeField::UpdateFromField(const Reference< css::sdb::XColumn >& _rxField, const Reference< XNumberFormatter >& /*xFormatter*/)
{
    lcl_setFormattedTime_nothrow(*static_cast<TimeControl*>(m_pWindow.get()), _rxField);
}

void DbTimeField::updateFromModel( Reference< XPropertySet > _rxModel )
{
    OSL_ENSURE( _rxModel.is() && m_pWindow, "DbTimeField::updateFromModel: invalid call!" );

    FormattedControlBase* pControl = static_cast<FormattedControlBase*>(m_pWindow.get());
    weld::TimeFormatter& rControlFormatter = static_cast<weld::TimeFormatter&>(pControl->get_formatter());

    util::Time aTime;
    if ( _rxModel->getPropertyValue( FM_PROP_TIME ) >>= aTime )
        rControlFormatter.SetTime(::tools::Time(aTime));
    else
        pControl->get_widget().set_text(OUString());
}

bool DbTimeField::commitControl()
{
    FormattedControlBase* pControl = static_cast<FormattedControlBase*>(m_pWindow.get());
    OUString aText(pControl->get_widget().get_text());
    Any aVal;

    if (!aText.isEmpty())   // not empty
    {
        weld::TimeFormatter& rControlFormatter = static_cast<weld::TimeFormatter&>(pControl->get_formatter());
        aVal <<= rControlFormatter.GetTime().GetUNOTime();
    }

    m_rColumn.getModel()->setPropertyValue(FM_PROP_TIME, aVal);
    return true;
}

DbComboBox::DbComboBox(DbGridColumn& _rColumn)
           :DbCellControl(_rColumn)
{
    setAlignedController( false );

    doPropertyListening( FM_PROP_STRINGITEMLIST );
    doPropertyListening( FM_PROP_LINECOUNT );
}

void DbComboBox::_propertyChanged( const PropertyChangeEvent& _rEvent )
{
    if ( _rEvent.PropertyName == FM_PROP_STRINGITEMLIST )
    {
        SetList(_rEvent.NewValue);
    }
    else
    {
        DbCellControl::_propertyChanged( _rEvent ) ;
    }
}

void DbComboBox::SetList(const Any& rItems)
{
    ComboBoxControl* pField = static_cast<ComboBoxControl*>(m_pWindow.get());
    weld::ComboBox& rComboBox = pField->get_widget();
    rComboBox.clear();

    css::uno::Sequence<OUString> aTest;
    if (rItems >>= aTest)
    {
        for (const OUString& rString : aTest)
             rComboBox.append_text(rString);

        // tell the grid control that this controller is invalid and has to be re-initialized
        invalidatedController();
    }
}

void DbComboBox::implAdjustGenericFieldSetting(const Reference<XPropertySet>&)
{
    // we no longer pay attention to FM_PROP_LINECOUNT
}

void DbComboBox::Init(BrowserDataWin& rParent, const Reference< XRowSet >& xCursor)
{
    m_rColumn.SetAlignmentFromModel(css::awt::TextAlign::LEFT);

    m_pWindow = VclPtr<ComboBoxControl>::Create( &rParent );

    // selection from right to left
    AllSettings     aSettings = m_pWindow->GetSettings();
    StyleSettings   aStyleSettings = aSettings.GetStyleSettings();
    aStyleSettings.SetSelectionOptions(
        aStyleSettings.GetSelectionOptions() | SelectionOptions::ShowFirst);
    aSettings.SetStyleSettings(aStyleSettings);
    m_pWindow->SetSettings(aSettings, true);

    // some initial properties
    Reference< XPropertySet >   xModel(m_rColumn.getModel());
    SetList( xModel->getPropertyValue( FM_PROP_STRINGITEMLIST ) );
    implAdjustGenericFieldSetting( xModel );

    DbCellControl::Init( rParent, xCursor );
}

CellControllerRef DbComboBox::CreateController() const
{
    return new ComboBoxCellController(static_cast<ComboBoxControl*>(m_pWindow.get()));
}

OUString DbComboBox::GetFormatText(const Reference< css::sdb::XColumn >& _rxField, const Reference< XNumberFormatter >& xFormatter, const Color** /*ppColor*/)
{
    const css::uno::Reference<css::beans::XPropertySet> xPS(_rxField, UNO_QUERY);
    ::dbtools::FormattedColumnValue fmter( xFormatter, xPS );

    return fmter.getFormattedValue();
}

void DbComboBox::UpdateFromField(const Reference< css::sdb::XColumn >& _rxField, const Reference< XNumberFormatter >& xFormatter)
{
    ComboBoxControl* pControl = static_cast<ComboBoxControl*>(m_pWindow.get());
    pControl->get_widget().set_entry_text(GetFormatText(_rxField, xFormatter));
}

void DbComboBox::updateFromModel( Reference< XPropertySet > _rxModel )
{
    OSL_ENSURE( _rxModel.is() && m_pWindow, "DbComboBox::updateFromModel: invalid call!" );

    OUString sText;
    _rxModel->getPropertyValue( FM_PROP_TEXT ) >>= sText;

    ComboBoxControl* pControl = static_cast<ComboBoxControl*>(m_pWindow.get());
    weld::ComboBox& rComboBox = pControl->get_widget();

    OUString sOldActive = rComboBox.get_active_text();
    rComboBox.set_entry_text(sText);
    rComboBox.select_entry_region(0, -1);

    if (sOldActive != rComboBox.get_active_text())
        pControl->TriggerAuxModify();
}

bool DbComboBox::commitControl()
{
    ComboBoxControl* pControl = static_cast<ComboBoxControl*>(m_pWindow.get());
    weld::ComboBox& rComboBox = pControl->get_widget();
    OUString aText(rComboBox.get_active_text());
    m_rColumn.getModel()->setPropertyValue(FM_PROP_TEXT, Any(aText));
    return true;
}


DbListBox::DbListBox(DbGridColumn& _rColumn)
          :DbCellControl(_rColumn)
          ,m_bBound(false)
{
    setAlignedController( false );

    doPropertyListening( FM_PROP_STRINGITEMLIST );
    doPropertyListening( FM_PROP_LINECOUNT );
}

void DbListBox::_propertyChanged( const css::beans::PropertyChangeEvent& _rEvent )
{
    if ( _rEvent.PropertyName == FM_PROP_STRINGITEMLIST )
    {
        SetList(_rEvent.NewValue);
    }
    else
    {
        DbCellControl::_propertyChanged( _rEvent ) ;
    }
}

void DbListBox::SetList(const Any& rItems)
{
    ListBoxControl* pField = static_cast<ListBoxControl*>(m_pWindow.get());

    weld::ComboBox& rFieldList = pField->get_widget();

    rFieldList.clear();
    m_bBound = false;

    css::uno::Sequence<OUString> aTest;
    if (!(rItems >>= aTest))
        return;

    if (aTest.hasElements())
    {
        for (const OUString& rString : aTest)
             rFieldList.append_text(rString);

        m_rColumn.getModel()->getPropertyValue(FM_PROP_VALUE_SEQ) >>= m_aValueList;
        m_bBound = m_aValueList.hasElements();

        // tell the grid control that this controller is invalid and has to be re-initialized
        invalidatedController();
    }
}

void DbListBox::Init(BrowserDataWin& rParent, const Reference< XRowSet >& xCursor)
{
    m_rColumn.SetAlignment(css::awt::TextAlign::LEFT);

    m_pWindow = VclPtr<ListBoxControl>::Create( &rParent );

    // some initial properties
    Reference< XPropertySet > xModel( m_rColumn.getModel() );
    SetList( xModel->getPropertyValue( FM_PROP_STRINGITEMLIST ) );
    implAdjustGenericFieldSetting( xModel );

    DbCellControl::Init( rParent, xCursor );
}

void DbListBox::implAdjustGenericFieldSetting(const Reference<XPropertySet>& _rxModel)
{
    DBG_ASSERT( m_pWindow, "DbListBox::implAdjustGenericFieldSetting: not to be called without window!" );
    DBG_ASSERT( _rxModel.is(), "DbListBox::implAdjustGenericFieldSetting: invalid model!" );
    if ( m_pWindow && _rxModel.is() )
    {
        sal_Int16  nLines   = getINT16( _rxModel->getPropertyValue( FM_PROP_LINECOUNT ) );
        weld::ComboBox& rComboBox = static_cast<ListBoxControl*>(m_pWindow.get())->get_widget();
        rComboBox.set_max_drop_down_rows(nLines);
    }
}

CellControllerRef DbListBox::CreateController() const
{
    return new ListBoxCellController(static_cast<ListBoxControl*>(m_pWindow.get()));
}

OUString DbListBox::GetFormatText(const Reference< css::sdb::XColumn >& _rxField, const Reference< XNumberFormatter >& /*xFormatter*/, const Color** /*ppColor*/)
{
    OUString sText;
    if ( _rxField.is() )
    {
        try
        {
            sText = _rxField->getString();
            if ( m_bBound )
            {
                sal_Int32 nPos = ::comphelper::findValue( m_aValueList, sText );
                if ( nPos != -1 )
                    sText = static_cast<svt::ListBoxControl*>(m_pWindow.get())->get_widget().get_text(nPos);
                else
                    sText.clear();
            }
        }
        catchconst Exception& )
        {
            DBG_UNHANDLED_EXCEPTION("svx");
        }
    }
    return sText;
}

void DbListBox::UpdateFromField(const Reference< css::sdb::XColumn >& _rxField, const Reference< XNumberFormatter >& xFormatter)
{
    OUString sFormattedText( GetFormatText( _rxField, xFormatter ) );
    weld::ComboBox& rComboBox = static_cast<ListBoxControl*>(m_pWindow.get())->get_widget();
    if (!sFormattedText.isEmpty())
        rComboBox.set_active_text(sFormattedText);
    else
        rComboBox.set_active(-1);
}

void DbListBox::updateFromModel( Reference< XPropertySet > _rxModel )
{
    OSL_ENSURE( _rxModel.is() && m_pWindow, "DbListBox::updateFromModel: invalid call!" );

    Sequence< sal_Int16 > aSelection;
    _rxModel->getPropertyValue( FM_PROP_SELECT_SEQ ) >>= aSelection;

    sal_Int16 nSelection = -1;
    if ( aSelection.hasElements() )
        nSelection = aSelection[ 0 ];

    ListBoxControl* pControl = static_cast<ListBoxControl*>(m_pWindow.get());
    weld::ComboBox& rComboBox = pControl->get_widget();

    int nOldActive = rComboBox.get_active();
    if (nSelection >= 0 && nSelection < rComboBox.get_count())
        rComboBox.set_active(nSelection);
    else
        rComboBox.set_active(-1);

    if (nOldActive != rComboBox.get_active())
        pControl->TriggerAuxModify();
}

bool DbListBox::commitControl()
{
    Any aVal;
    Sequence<sal_Int16> aSelectSeq;
    weld::ComboBox& rComboBox = static_cast<ListBoxControl*>(m_pWindow.get())->get_widget();
    auto nActive = rComboBox.get_active();
    if (nActive != -1)
    {
        aSelectSeq.realloc(1);
        *aSelectSeq.getArray() = static_cast<sal_Int16>(nActive);
    }
    aVal <<= aSelectSeq;
    m_rColumn.getModel()->setPropertyValue(FM_PROP_SELECT_SEQ, aVal);
    return true;
}

DbFilterField::DbFilterField(const Reference< XComponentContext >& rxContext,DbGridColumn& _rColumn)
              :DbCellControl(_rColumn)
              ,OSQLParserClient(rxContext)
              ,m_nControlClass(css::form::FormComponentType::TEXTFIELD)
              ,m_bFilterList(false)
              ,m_bFilterListFilled(false)
{

    setAlignedController( false );
}

DbFilterField::~DbFilterField()
{
    if (m_nControlClass == css::form::FormComponentType::CHECKBOX)
        static_cast<CheckBoxControl*>(m_pWindow.get())->SetToggleHdl(Link<weld::CheckButton&,pan style='color:red'>void>());

}

void DbFilterField::PaintCell(OutputDevice& rDev, const tools::Rectangle& rRect)
{
    static const DrawTextFlags nStyle = DrawTextFlags::Clip | DrawTextFlags::VCenter | DrawTextFlags::Left;
    switch (m_nControlClass)
    {
        case FormComponentType::CHECKBOX:
        {
            // center the checkbox within the space available
            CheckBoxControl* pControl = static_cast<CheckBoxControl*>(m_pPainter.get());
            Size aBoxSize = pControl->GetBox().get_preferred_size();
            tools::Rectangle aRect(Point(rRect.Left() + ((rRect.GetWidth() - aBoxSize.Width()) / 2),
                                         rRect.Top() + ((rRect.GetHeight() - aBoxSize.Height()) / 2)),
                                   aBoxSize);

            DbCellControl::PaintCell(rDev, aRect);
            break;
        }
        case FormComponentType::LISTBOX:
            rDev.DrawText(rRect, static_cast<ListBoxControl*>(m_pWindow.get())->get_widget().get_active_text(), nStyle);
            break;
        default:
            rDev.DrawText(rRect, m_aText, nStyle);
    }
}

void DbFilterField::SetList(const Any& rItems, bool bComboBox)
{
    css::uno::Sequence<OUString> aTest;
    rItems >>= aTest;
    if (!aTest.hasElements())
        return;

    if (bComboBox)
    {
        ComboBoxControl* pField = static_cast<ComboBoxControl*>(m_pWindow.get());
        weld::ComboBox& rComboBox = pField->get_widget();
        for (const OUString& rString : aTest)
            rComboBox.append_text(rString);
    }
    else
    {
        ListBoxControl* pField = static_cast<ListBoxControl*>(m_pWindow.get());
        weld::ComboBox& rFieldBox = pField->get_widget();
        for (const OUString& rString : aTest)
            rFieldBox.append_text(rString);

        m_rColumn.getModel()->getPropertyValue(FM_PROP_VALUE_SEQ) >>= m_aValueList;
    }
}

void DbFilterField::CreateControl(BrowserDataWin* pParent, const Reference< css::beans::XPropertySet >& xModel)
{
    switch (m_nControlClass)
    {
        case css::form::FormComponentType::CHECKBOX:
            m_pWindow = VclPtr<CheckBoxControl>::Create(pParent);
            m_pWindow->SetPaintTransparent( true );
            static_cast<CheckBoxControl*>(m_pWindow.get())->SetToggleHdl(LINK(this, DbFilterField, OnToggle));

            m_pPainter = VclPtr<CheckBoxControl>::Create(pParent);
            m_pPainter->SetPaintTransparent( true );
            m_pPainter->SetBackground();
            break;
        case css::form::FormComponentType::LISTBOX:
        {
            m_pWindow = VclPtr<ListBoxControl>::Create(pParent);
            Any  aItems = xModel->getPropertyValue(FM_PROP_STRINGITEMLIST);
            SetList(aItems, false);
        }   break;
        case css::form::FormComponentType::COMBOBOX:
        {
            m_pWindow = VclPtr<ComboBoxControl>::Create(pParent);

            AllSettings     aSettings = m_pWindow->GetSettings();
            StyleSettings   aStyleSettings = aSettings.GetStyleSettings();
            aStyleSettings.SetSelectionOptions(
                           aStyleSettings.GetSelectionOptions() | SelectionOptions::ShowFirst);
            aSettings.SetStyleSettings(aStyleSettings);
            m_pWindow->SetSettings(aSettings, true);

            if (!m_bFilterList)
            {
                Any aItems = xModel->getPropertyValue(FM_PROP_STRINGITEMLIST);
                SetList(aItems, true);
            }

        }   break;
        default:
        {
            m_pWindow  = VclPtr<EditControl>::Create(pParent);
            AllSettings     aSettings = m_pWindow->GetSettings();
            StyleSettings   aStyleSettings = aSettings.GetStyleSettings();
            aStyleSettings.SetSelectionOptions(
                           aStyleSettings.GetSelectionOptions() | SelectionOptions::ShowFirst);
            aSettings.SetStyleSettings(aStyleSettings);
            m_pWindow->SetSettings(aSettings, true);
        }
    }
}

void DbFilterField::Init(BrowserDataWin& rParent, const Reference< XRowSet >& xCursor)
{
    Reference< css::beans::XPropertySet >  xModel(m_rColumn.getModel());
    m_rColumn.SetAlignment(css::awt::TextAlign::LEFT);

    if (xModel.is())
    {
        m_bFilterList = ::comphelper::hasProperty(FM_PROP_FILTERPROPOSAL, xModel) && ::comphelper::getBOOL(xModel->getPropertyValue(FM_PROP_FILTERPROPOSAL));
        if (m_bFilterList)
            m_nControlClass = css::form::FormComponentType::COMBOBOX;
        else
        {
            sal_Int16 nClassId = ::comphelper::getINT16(xModel->getPropertyValue(FM_PROP_CLASSID));
            switch (nClassId)
            {
                case FormComponentType::CHECKBOX:
                case FormComponentType::LISTBOX:
                case FormComponentType::COMBOBOX:
                    m_nControlClass = nClassId;
                    break;
                default:
                    if (m_bFilterList)
                        m_nControlClass = FormComponentType::COMBOBOX;
                    else
                        m_nControlClass = FormComponentType::TEXTFIELD;
            }
        }
    }

    CreateControl( &rParent, xModel );
    DbCellControl::Init( rParent, xCursor );

    // filter cells are never readonly
    m_pWindow->SetEditableReadOnly(false);
}

CellControllerRef DbFilterField::CreateController() const
{
    CellControllerRef xController;
    switch (m_nControlClass)
    {
        case css::form::FormComponentType::CHECKBOX:
            xController = new CheckBoxCellController(static_cast<CheckBoxControl*>(m_pWindow.get()));
            break;
        case css::form::FormComponentType::LISTBOX:
            xController = new ListBoxCellController(static_cast<ListBoxControl*>(m_pWindow.get()));
            break;
        case css::form::FormComponentType::COMBOBOX:
            xController = new ComboBoxCellController(static_cast<ComboBoxControl*>(m_pWindow.get()));
            break;
        default:
            if (m_bFilterList)
                xController = new ComboBoxCellController(static_cast<ComboBoxControl*>(m_pWindow.get()));
            else
                xController = new EditCellController(static_cast<EditControlBase*>(m_pWindow.get()));
    }
    return xController;
}

void DbFilterField::updateFromModel( Reference< XPropertySet > _rxModel )
{
    OSL_ENSURE( _rxModel.is() && m_pWindow, "DbFilterField::updateFromModel: invalid call!" );

    OSL_FAIL( "DbFilterField::updateFromModel: not implemented yet (how the hell did you reach this?)!" );
    // TODO: implement this.
    // remember: updateFromModel should be some kind of opposite of commitControl
}

bool DbFilterField::commitControl()
{
    OUString aText(m_aText);
    switch (m_nControlClass)
    {
        case css::form::FormComponentType::CHECKBOX:
            return true;
        case css::form::FormComponentType::LISTBOX:
        {
            aText.clear();
            weld::ComboBox& rComboBox = static_cast<svt::ListBoxControl*>(m_pWindow.get())->get_widget();
            auto nActive = rComboBox.get_active();
            if (nActive != -1)
            {
                sal_Int16 nPos = static_cast<sal_Int16>(nActive);
                if ( ( nPos >= 0 ) && ( nPos < m_aValueList.getLength() ) )
                    aText = m_aValueList.getConstArray()[nPos];
            }

            if (m_aText != aText)
            {
                m_aText = aText;
                m_aCommitLink.Call(*this);
            }
            return true;
        }
        case css::form::FormComponentType::COMBOBOX:
        {
            aText = static_cast<ComboBoxControl*>(m_pWindow.get())->get_widget().get_active_text();
            break;
        }
        default:
        {
            aText = static_cast<EditControlBase*>(m_pWindow.get())->get_widget().get_text();
            break;
        }
    }

    if (m_aText != aText)
    {
        // check the text with the SQL-Parser
        OUString aNewText(comphelper::string::stripEnd(aText, ' '));
        if (!aNewText.isEmpty())
        {
            OUString aErrorMsg;
            Reference< XNumberFormatter >  xNumberFormatter(m_rColumn.GetParent().getNumberFormatter());

            std::unique_ptr< OSQLParseNode > pParseNode = predicateTree(aErrorMsg, aNewText,xNumberFormatter, m_rColumn.GetField());
            if (pParseNode != nullptr)
            {
                OUString aPreparedText;

                css::lang::Locale aAppLocale = Application::GetSettings().GetUILanguageTag().getLocale();

                Reference< XRowSet > xDataSourceRowSet(
                    Reference< XInterface >(*m_rColumn.GetParent().getDataSource()), UNO_QUERY);
                Reference< XConnection >  xConnection(getConnection(xDataSourceRowSet));

                pParseNode->parseNodeToPredicateStr(aPreparedText,
                                                    xConnection,
                                                    xNumberFormatter,
                                                    m_rColumn.GetField(),
                                                    OUString(),
                                                    aAppLocale,
                                                    u"."_ustr,
                                                    getParseContext());
                m_aText = aPreparedText;
            }
            else
            {

                SQLException aError(aErrorMsg, {}, {}, 0, {});
                displayException(aError, VCLUnoHelper::GetInterface(m_pWindow->GetParent()));
                    // TODO: transport the title

                return false;
            }
        }
        else
            m_aText = aText;

        m_pWindow->SetText(m_aText);
        m_aCommitLink.Call(*this);
    }
    return true;
}


void DbFilterField::SetText(const OUString& rText)
{
    m_aText = rText;
    switch (m_nControlClass)
    {
        case css::form::FormComponentType::CHECKBOX:
        {
            TriState eState;
            if (rText == "1")
                eState = TRISTATE_TRUE;
            else if (rText == "0")
                eState = TRISTATE_FALSE;
            else
                eState = TRISTATE_INDET;

            static_cast<CheckBoxControl*>(m_pWindow.get())->SetState(eState);
            static_cast<CheckBoxControl*>(m_pPainter.get())->SetState(eState);
        }   break;
        case css::form::FormComponentType::LISTBOX:
        {
            sal_Int32 nPos = ::comphelper::findValue(m_aValueList, m_aText);
            static_cast<ListBoxControl*>(m_pWindow.get())->get_widget().set_active(nPos);
        }   break;
        case css::form::FormComponentType::COMBOBOX:
        {
            static_cast<ComboBoxControl*>(m_pWindow.get())->get_widget().set_entry_text(m_aText);
            break;
        }
        default:
        {
            static_cast<EditControlBase*>(m_pWindow.get())->get_widget().set_text(m_aText);
            break;
        }
    }

    // now force a repaint on the window
    m_rColumn.GetParent().RowModified(0);
}


void DbFilterField::Update()
{
    // should we fill the combobox with a filter proposal?
    if (!m_bFilterList || m_bFilterListFilled)
        return;

    m_bFilterListFilled = true;
    Reference< css::beans::XPropertySet >  xField = m_rColumn.GetField();
    if (!xField.is())
        return;

    OUString aName;
    xField->getPropertyValue(FM_PROP_NAME) >>= aName;

    // the columnmodel
    Reference< css::container::XChild >  xModelAsChild(m_rColumn.getModel(), UNO_QUERY);
    // the grid model
    xModelAsChild.set(xModelAsChild->getParent(),UNO_QUERY);
    Reference< XRowSet >  xForm(xModelAsChild->getParent(), UNO_QUERY);
    if (!xForm.is())
        return;

    Reference<XPropertySet> xFormProp(xForm,UNO_QUERY);
    Reference< XTablesSupplier > xSupTab;
    xFormProp->getPropertyValue(u"SingleSelectQueryComposer"_ustr) >>= xSupTab;

    Reference< XConnection >  xConnection(getConnection(xForm));
    if (!xSupTab.is())
        return;

    // search the field
    Reference< XColumnsSupplier > xSupCol(xSupTab,UNO_QUERY);
    Reference< css::container::XNameAccess >    xFieldNames = xSupCol->getColumns();
    if (!xFieldNames->hasByName(aName))
        return;

    Reference< css::container::XNameAccess >    xTablesNames = xSupTab->getTables();
    Reference< css::beans::XPropertySet >       xComposerFieldAsSet(xFieldNames->getByName(aName),UNO_QUERY);

    if (!xComposerFieldAsSet.is() ||
        !::comphelper::hasProperty(FM_PROP_TABLENAME, xComposerFieldAsSet) ||
        !::comphelper::hasProperty(FM_PROP_FIELDSOURCE, xComposerFieldAsSet))
        return;

    OUString aFieldName;
    OUString aTableName;
    xComposerFieldAsSet->getPropertyValue(FM_PROP_FIELDSOURCE)  >>= aFieldName;
    xComposerFieldAsSet->getPropertyValue(FM_PROP_TABLENAME)    >>= aTableName;

    // no possibility to create a select statement
    // looking for the complete table name
    if (!xTablesNames->hasByName(aTableName))
        return;

    // build a statement and send as query;
    // Access to the connection
    Reference< XStatement >  xStatement;
    Reference< XResultSet >  xListCursor;
    Reference< css::sdb::XColumn >  xDataField;

    try
    {
        Reference< XDatabaseMetaData >  xMeta = xConnection->getMetaData();

        OUString aQuote(xMeta->getIdentifierQuoteString());
        OUStringBuffer aStatement("SELECT DISTINCT "
            + quoteName(aQuote, aName));
        if (!aFieldName.isEmpty() && aName != aFieldName)
        {
            aStatement.append(" AS "
                + quoteName(aQuote, aFieldName));
        }

        aStatement.append(" FROM ");

        Reference< XPropertySet > xTableNameAccess(xTablesNames->getByName(aTableName), UNO_QUERY_THROW);
        aStatement.append(composeTableNameForSelect(xConnection, xTableNameAccess));

        xStatement = xConnection->createStatement();
        Reference< css::beans::XPropertySet >  xStatementProps(xStatement, UNO_QUERY);
        xStatementProps->setPropertyValue(FM_PROP_ESCAPE_PROCESSING, Any(true));

        xListCursor = xStatement->executeQuery(aStatement.makeStringAndClear());

        Reference< css::sdbcx::XColumnsSupplier >  xSupplyCols(xListCursor, UNO_QUERY);
        Reference< css::container::XIndexAccess >  xFields(xSupplyCols->getColumns(), UNO_QUERY);
        xDataField.set(xFields->getByIndex(0), css::uno::UNO_QUERY);
        if (!xDataField.is())
            return;
    }
    catch(const Exception&)
    {
        ::comphelper::disposeComponent(xStatement);
        return;
    }

    sal_Int16 i = 0;
    ::std::vector< OUString >   aStringList;
    aStringList.reserve(16);
    OUString aStr;
    css::util::Date aNullDate = m_rColumn.GetParent().getNullDate();
    sal_Int32 nFormatKey = m_rColumn.GetKey();
    Reference< XNumberFormatter >  xFormatter = m_rColumn.GetParent().getNumberFormatter();
    sal_Int16 nKeyType = ::comphelper::getNumberFormatType(xFormatter->getNumberFormatsSupplier()->getNumberFormats(), nFormatKey);

    while (!xListCursor->isAfterLast() && i++ < SHRT_MAX) // max number of entries
    {
        aStr = getFormattedValue(xDataField, xFormatter, aNullDate, nFormatKey, nKeyType);
        aStringList.push_back(aStr);
        (void)xListCursor->next();
    }

    ComboBoxControl* pField = static_cast<ComboBoxControl*>(m_pWindow.get());
    weld::ComboBox& rComboBox = pField->get_widget();
    // filling the entries for the combobox
    for (const auto& rString : aStringList)
        rComboBox.append_text(rString);
}

OUString DbFilterField::GetFormatText(const Reference< XColumn >& /*_rxField*/, const Reference< XNumberFormatter >& /*xFormatter*/, const Color** /*ppColor*/)
{
    return OUString();
}

void DbFilterField::UpdateFromField(const Reference< XColumn >& /*_rxField*/, const Reference< XNumberFormatter >& /*xFormatter*/)
{
    OSL_FAIL( "DbFilterField::UpdateFromField: cannot update a filter control from a field!" );
}

IMPL_LINK_NOARG(DbFilterField, OnToggle, weld::CheckButton&, void)
{
    TriState eState = static_cast<CheckBoxControl*>(m_pWindow.get())->GetState();
    OUStringBuffer aTextBuf;

    Reference< XRowSet > xDataSourceRowSet(
                    Reference< XInterface >(*m_rColumn.GetParent().getDataSource()), UNO_QUERY);
    Reference< XConnection >  xConnection(getConnection(xDataSourceRowSet));
    const sal_Int32 nBooleanComparisonMode = ::dbtools::DatabaseMetaData( xConnection ).getBooleanComparisonMode();

    switch (eState)
    {
        case TRISTATE_TRUE:
            ::dbtools::getBooleanComparisonPredicate(u""true, nBooleanComparisonMode, aTextBuf);
            break;
        case TRISTATE_FALSE:
            ::dbtools::getBooleanComparisonPredicate(u""false, nBooleanComparisonMode, aTextBuf);
            break;
        case TRISTATE_INDET:
            break;
    }

    const OUString aText(aTextBuf.makeStringAndClear());

    if (m_aText != aText)
    {
        m_aText = aText;
        m_aCommitLink.Call(*this);
    }
}

FmXGridCell::FmXGridCell( DbGridColumn* pColumn, std::unique_ptr<DbCellControl> _pControl )
            :OComponentHelper(m_aMutex)
            ,m_pColumn(pColumn)
            ,m_pCellControl( std::move(_pControl) )
            ,m_aWindowListeners( m_aMutex )
            ,m_aFocusListeners( m_aMutex )
            ,m_aKeyListeners( m_aMutex )
            ,m_aMouseListeners( m_aMutex )
            ,m_aMouseMotionListeners( m_aMutex )
{
}

void FmXGridCell::init()
{
    svt::ControlBase* pEventWindow( getEventWindow() );
    if ( pEventWindow )
    {
        pEventWindow->SetFocusInHdl(LINK( this, FmXGridCell, OnFocusGained));
        pEventWindow->SetFocusOutHdl(LINK( this, FmXGridCell, OnFocusLost));
        pEventWindow->SetMousePressHdl(LINK( this, FmXGridCell, OnMousePress));
        pEventWindow->SetMouseReleaseHdl(LINK( this, FmXGridCell, OnMouseRelease));
        pEventWindow->SetMouseMoveHdl(LINK( this, FmXGridCell, OnMouseMove));
        pEventWindow->SetKeyInputHdl( LINK( this, FmXGridCell, OnKeyInput) );
        pEventWindow->SetKeyReleaseHdl( LINK( this, FmXGridCell, OnKeyRelease) );
    }
}

svt::ControlBase* FmXGridCell::getEventWindow() const
{
    if ( m_pCellControl )
        return &m_pCellControl->GetWindow();
    return nullptr;
}

FmXGridCell::~FmXGridCell()
{
    if (!OComponentHelper::rBHelper.bDisposed)
    {
        acquire();
        dispose();
    }

}

void FmXGridCell::SetTextLineColor()
{
    if (m_pCellControl)
        m_pCellControl->SetTextLineColor();
}

void FmXGridCell::SetTextLineColor(const Color& _rColor)
{
    if (m_pCellControl)
        m_pCellControl->SetTextLineColor(_rColor);
}

// XTypeProvider

Sequence< Type > SAL_CALL FmXGridCell::getTypes( )
{
    Sequence< uno::Type > aTypes = ::comphelper::concatSequences(
        ::cppu::OComponentHelper::getTypes(),
        FmXGridCell_Base::getTypes()
    );
    if ( m_pCellControl )
        aTypes = ::comphelper::concatSequences(
            aTypes,
            FmXGridCell_WindowBase::getTypes()
        );
    return aTypes;
}


IMPLEMENT_GET_IMPLEMENTATION_ID( FmXGridCell )

// OComponentHelper

void FmXGridCell::disposing()
{
    lang::EventObject aEvent( *this );
    m_aWindowListeners.disposeAndClear( aEvent );
    m_aFocusListeners.disposeAndClear( aEvent );
    m_aKeyListeners.disposeAndClear( aEvent );
    m_aMouseListeners.disposeAndClear( aEvent );
    m_aMouseMotionListeners.disposeAndClear( aEvent );

    OComponentHelper::disposing();
    m_pColumn = nullptr;
    m_pCellControl.reset();
}


Any SAL_CALL FmXGridCell::queryAggregation( const css::uno::Type& _rType )
{
    Any aReturn = OComponentHelper::queryAggregation( _rType );

    if ( !aReturn.hasValue() )
        aReturn = FmXGridCell_Base::queryInterface( _rType );

    if ( !aReturn.hasValue() && ( m_pCellControl != nullptr ) )
        aReturn = FmXGridCell_WindowBase::queryInterface( _rType );

    return aReturn;
}

// css::awt::XControl

Reference< XInterface >  FmXGridCell::getContext()
{
    return Reference< XInterface > ();
}


Reference< css::awt::XControlModel >  FmXGridCell::getModel()
{
    checkDisposed(OComponentHelper::rBHelper.bDisposed);
    return Reference< css::awt::XControlModel > (m_pColumn->getModel(), UNO_QUERY);
}

// css::form::XBoundControl

sal_Bool FmXGridCell::getLock()
{
    checkDisposed(OComponentHelper::rBHelper.bDisposed);
    return m_pColumn->isLocked();
}


void FmXGridCell::setLock(sal_Bool _bLock)
{
    checkDisposed(OComponentHelper::rBHelper.bDisposed);
    if (getLock() == _bLock)
        return;
    else
    {
        ::osl::MutexGuard aGuard(m_aMutex);
        m_pColumn->setLock(_bLock);
    }
}


void SAL_CALL FmXGridCell::setPosSize( ::sal_Int32, ::sal_Int32, ::sal_Int32, ::sal_Int32, ::sal_Int16 )
{
    OSL_FAIL( "FmXGridCell::setPosSize: not implemented" );
    // not allowed to tamper with this for a grid cell
}


awt::Rectangle SAL_CALL FmXGridCell::getPosSize(  )
{
    OSL_FAIL( "FmXGridCell::getPosSize: not implemented" );
    return awt::Rectangle();
}


void SAL_CALL FmXGridCell::setVisible( sal_Bool )
{
    OSL_FAIL( "FmXGridCell::setVisible: not implemented" );
    // not allowed to tamper with this for a grid cell
}


void SAL_CALL FmXGridCell::setEnable( sal_Bool )
{
    OSL_FAIL( "FmXGridCell::setEnable: not implemented" );
    // not allowed to tamper with this for a grid cell
}


void SAL_CALL FmXGridCell::setFocus(  )
{
    OSL_FAIL( "FmXGridCell::setFocus: not implemented" );
    // not allowed to tamper with this for a grid cell
}


void SAL_CALL FmXGridCell::addWindowListener( const Reference< awt::XWindowListener >&&nbsp;_rxListener )
{
    checkDisposed(OComponentHelper::rBHelper.bDisposed);
    m_aWindowListeners.addInterface( _rxListener );
}


void SAL_CALL FmXGridCell::removeWindowListener( const Reference< awt::XWindowListener >&&nbsp;_rxListener )
{
    checkDisposed(OComponentHelper::rBHelper.bDisposed);
    m_aWindowListeners.removeInterface( _rxListener );
}


void SAL_CALL FmXGridCell::addFocusListener( const Reference< awt::XFocusListener >& _rxListener )
{
    checkDisposed(OComponentHelper::rBHelper.bDisposed);
    m_aFocusListeners.addInterface( _rxListener );
}


void SAL_CALL FmXGridCell::removeFocusListener( const Reference< awt::XFocusListener >&&nbsp;_rxListener )
{
    checkDisposed(OComponentHelper::rBHelper.bDisposed);
    m_aFocusListeners.removeInterface( _rxListener );
}


void SAL_CALL FmXGridCell::addKeyListener( const Reference< awt::XKeyListener >& _rxListener )
{
    checkDisposed(OComponentHelper::rBHelper.bDisposed);
    m_aKeyListeners.addInterface( _rxListener );
}


void SAL_CALL FmXGridCell::removeKeyListener( const Reference< awt::XKeyListener >& _rxListener )
{
    checkDisposed(OComponentHelper::rBHelper.bDisposed);
    m_aKeyListeners.removeInterface( _rxListener );
}


void SAL_CALL FmXGridCell::addMouseListener( const Reference< awt::XMouseListener >& _rxListener )
{
    checkDisposed(OComponentHelper::rBHelper.bDisposed);
    m_aMouseListeners.addInterface( _rxListener );
}


void SAL_CALL FmXGridCell::removeMouseListener( const Reference< awt::XMouseListener >&&nbsp;_rxListener )
{
    checkDisposed(OComponentHelper::rBHelper.bDisposed);
    m_aMouseListeners.removeInterface( _rxListener );
}


void SAL_CALL FmXGridCell::addMouseMotionListener( const Reference< awt::XMouseMotionListener >& _rxListener )
{
    checkDisposed(OComponentHelper::rBHelper.bDisposed);
    m_aMouseMotionListeners.addInterface( _rxListener );
}


void SAL_CALL FmXGridCell::removeMouseMotionListener( const Reference< awt::XMouseMotionListener >& _rxListener )
{
    checkDisposed(OComponentHelper::rBHelper.bDisposed);
    m_aMouseMotionListeners.removeInterface( _rxListener );
}

void SAL_CALL FmXGridCell::addPaintListener( const Reference< awt::XPaintListener >& )
{
    OSL_FAIL( "FmXGridCell::addPaintListener: not implemented" );
}

void SAL_CALL FmXGridCell::removePaintListener( const Reference< awt::XPaintListener >&&nbsp;)
{
    OSL_FAIL( "FmXGridCell::removePaintListener: not implemented" );
}

void FmXGridCell::onFocusGained( const awt::FocusEvent& _rEvent )
{
    checkDisposed(OComponentHelper::rBHelper.bDisposed);
    m_aFocusListeners.notifyEach( &awt::XFocusListener::focusGained, _rEvent );
}

void FmXGridCell::onFocusLost( const awt::FocusEvent& _rEvent )
{
    checkDisposed(OComponentHelper::rBHelper.bDisposed);
    m_aFocusListeners.notifyEach( &awt::XFocusListener::focusLost, _rEvent );
}

IMPL_LINK_NOARG(FmXGridCell, OnFocusGained, LinkParamNone*, void)
{
    if (!m_aFocusListeners.getLength())
        return;

    awt::FocusEvent aEvent;
    aEvent.Source = *this;
    aEvent.Temporary = false;

    onFocusGained(aEvent);
}

IMPL_LINK_NOARG(FmXGridCell, OnFocusLost, LinkParamNone*, void)
{
    if (!m_aFocusListeners.getLength())
        return;

    awt::FocusEvent aEvent;
    aEvent.Source = *this;
    aEvent.Temporary = false;

    onFocusLost(aEvent);
}

IMPL_LINK(FmXGridCell, OnMousePress, const MouseEvent&, rEventData, void)
{
    if (!m_aMouseListeners.getLength())
        return;

    awt::MouseEvent aEvent(VCLUnoHelper::createMouseEvent(rEventData, *this));
    m_aMouseListeners.notifyEach(&awt::XMouseListener::mousePressed, aEvent);
}

IMPL_LINK(FmXGridCell, OnMouseRelease, const MouseEvent&, rEventData, void)
{
    if (!m_aMouseListeners.getLength())
        return;

    awt::MouseEvent aEvent(VCLUnoHelper::createMouseEvent(rEventData, *this));
    m_aMouseListeners.notifyEach(&awt::XMouseListener::mouseReleased, aEvent);
}

IMPL_LINK(FmXGridCell, OnMouseMove, const MouseEvent&, rMouseEvent, void)
{
    if ( rMouseEvent.IsEnterWindow() || rMouseEvent.IsLeaveWindow() )
    {
        if ( m_aMouseListeners.getLength() != 0 )
        {
            awt::MouseEvent aEvent( VCLUnoHelper::createMouseEvent( rMouseEvent, *this ) );
            m_aMouseListeners.notifyEach( rMouseEvent.IsEnterWindow() ? &awt::XMouseListener::mouseEntered: &awt::XMouseListener::mouseExited, aEvent );
        }
    }
    else if ( !rMouseEvent.IsEnterWindow() && !rMouseEvent.IsLeaveWindow() )
    {
        if ( m_aMouseMotionListeners.getLength() != 0 )
        {
            awt::MouseEvent aEvent( VCLUnoHelper::createMouseEvent( rMouseEvent, *this ) );
            aEvent.ClickCount = 0;
            const bool bSimpleMove = bool( rMouseEvent.GetMode() & MouseEventModifiers::SIMPLEMOVE );
            m_aMouseMotionListeners.notifyEach( bSimpleMove ? &awt::XMouseMotionListener::mouseMoved: &awt::XMouseMotionListener::mouseDragged, aEvent );
        }
    }
}

IMPL_LINK(FmXGridCell, OnKeyInput, const KeyEvent&, rEventData, void)
{
    if (!m_aKeyListeners.getLength())
        return;

    awt::KeyEvent aEvent(VCLUnoHelper::createKeyEvent(rEventData, *this));
    m_aKeyListeners.notifyEach(&awt::XKeyListener::keyPressed, aEvent);
}

IMPL_LINK(FmXGridCell, OnKeyRelease, const KeyEvent&, rEventData, void)
{
    if (!m_aKeyListeners.getLength())
        return;

    awt::KeyEvent aEvent(VCLUnoHelper::createKeyEvent(rEventData, *this));
    m_aKeyListeners.notifyEach(&awt::XKeyListener::keyReleased, aEvent);
}

void FmXDataCell::PaintFieldToCell(OutputDevice& rDev, const tools::Rectangle&&nbsp;rRect,
                        const Reference< css::sdb::XColumn >& _rxField,
                        const Reference< XNumberFormatter >& xFormatter)
{
    m_pCellControl->PaintFieldToCell( rDev, rRect, _rxField, xFormatter );
}

void FmXDataCell::UpdateFromColumn()
{
    Reference< css::sdb::XColumn >  xField(m_pColumn->GetCurrentFieldValue());
    if (xField.is())
        m_pCellControl->UpdateFromField(xField, m_pColumn->GetParent().getNumberFormatter());
}

FmXTextCell::FmXTextCell( DbGridColumn* pColumn, std::unique_ptr<DbCellControl> pControl )
    :FmXDataCell( pColumn, std::move(pControl) )
    ,m_bIsMultiLineText(false)
{
}

void FmXTextCell::PaintFieldToCell(OutputDevice& rDev,
                        const tools::Rectangle& rRect,
                        const Reference< css::sdb::XColumn >& _rxField,
                        const Reference< XNumberFormatter >& xFormatter)
{
    DrawTextFlags nStyle = DrawTextFlags::Clip;
    if ( ( rDev.GetOutDevType() == OUTDEV_WINDOW ) && !rDev.GetOwnerWindow()->IsEnabled() )
        nStyle |= DrawTextFlags::Disable;

    switch (m_pColumn->GetAlignment())
    {
        case css::awt::TextAlign::RIGHT:
            nStyle |= DrawTextFlags::Right;
            break;
        case css::awt::TextAlign::CENTER:
            nStyle |= DrawTextFlags::Center;
            break;
        default:
            nStyle |= DrawTextFlags::Left;
    }

    if (!m_bIsMultiLineText)
        nStyle |= DrawTextFlags::VCenter;
    else
        nStyle |= DrawTextFlags::Top | DrawTextFlags::MultiLine | DrawTextFlags::WordBreak;

    try
    {
        const Color* pColor = nullptr;
        OUString aText = GetText(_rxField, xFormatter, &pColor);
        if (pColor != nullptr)
        {
            Color aOldTextColor( rDev.GetTextColor() );
            rDev.SetTextColor( *pColor );
            rDev.DrawText(rRect, aText, nStyle);
            rDev.SetTextColor( aOldTextColor );
        }
        else
            rDev.DrawText(rRect, aText, nStyle);
    }
    catch (const Exception&)
    {
        TOOLS_WARN_EXCEPTION("svx.fmcomp""PaintFieldToCell");
    }
}

FmXEditCell::FmXEditCell( DbGridColumn* pColumn, std::unique_ptr<DbCellControl> pControl )
            :FmXTextCell( pColumn, std::move(pControl) )
            ,m_aTextListeners(m_aMutex)
            ,m_aChangeListeners( m_aMutex )
            ,m_pEditImplementation( nullptr )
            ,m_bOwnEditImplementation( false )
{

    DbTextField* pTextField = dynamic_cast<DbTextField*>( m_pCellControl.get()  );
    if ( pTextField )
    {

        m_pEditImplementation = pTextField->GetEditImplementation();
        m_bIsMultiLineText = pTextField->IsMultiLineEdit();
    }
    else
    {
        m_pEditImplementation = new EntryImplementation(static_cast<EditControlBase&>(m_pCellControl->GetWindow()));
        m_bOwnEditImplementation = true;
    }
    m_pEditImplementation->SetAuxModifyHdl(LINK(this, FmXEditCell, ModifyHdl));
}

FmXEditCell::~FmXEditCell()
{
    if (!OComponentHelper::rBHelper.bDisposed)
    {
        acquire();
        dispose();
    }
}

// OComponentHelper
void FmXEditCell::disposing()
{
    css::lang::EventObject aEvt(*this);
    m_aTextListeners.disposeAndClear(aEvt);
    m_aChangeListeners.disposeAndClear(aEvt);

    if ( m_bOwnEditImplementation )
        delete m_pEditImplementation;
    m_pEditImplementation = nullptr;

    FmXDataCell::disposing();
}

Any SAL_CALL FmXEditCell::queryAggregation( const css::uno::Type& _rType )
{
    Any aReturn = FmXTextCell::queryAggregation( _rType );

    if ( !aReturn.hasValue() )
        aReturn = FmXEditCell_Base::queryInterface( _rType );

    return aReturn;
}

Sequence< css::uno::Type > SAL_CALL FmXEditCell::getTypes(  )
{
    return ::comphelper::concatSequences(
        FmXTextCell::getTypes(),
        FmXEditCell_Base::getTypes()
    );
}

IMPLEMENT_GET_IMPLEMENTATION_ID( FmXEditCell )

// css::awt::XTextComponent
void SAL_CALL FmXEditCell::addTextListener(const Reference< css::awt::XTextListener >&&nbsp;l)
{
    m_aTextListeners.addInterface( l );
}


void SAL_CALL FmXEditCell::removeTextListener(const Reference< css::awt::XTextListener >& l)
{
    m_aTextListeners.removeInterface( l );
}

void SAL_CALL FmXEditCell::setText( const OUString& aText )
{
    ::osl::MutexGuard aGuard( m_aMutex );

    if ( m_pEditImplementation )
    {
        m_pEditImplementation->SetText( aText );

        // In Java, a textChanged is fired as well; not in VCL.
        // css::awt::Toolkit must be Java-compliant...
        onTextChanged();
    }
}

void SAL_CALL FmXEditCell::insertText(const css::awt::Selection& rSel, const OUString& aText)
{
    ::osl::MutexGuard aGuard( m_aMutex );

    if ( m_pEditImplementation )
    {
        m_pEditImplementation->SetSelection( Selection( rSel.Min, rSel.Max ) );
        m_pEditImplementation->ReplaceSelected( aText );
    }
}

OUString SAL_CALL FmXEditCell::getText()
{
    ::osl::MutexGuard aGuard( m_aMutex );

    OUString aText;
    if ( m_pEditImplementation )
    {
        if ( m_pEditImplementation->GetControl().IsVisible() && m_pColumn->GetParent().getDisplaySynchron())
        {
            // if the display isn't sync with the cursor we can't ask the edit field
            LineEnd eLineEndFormat = getModelLineEndSetting( m_pColumn->getModel() );
            aText = m_pEditImplementation->GetText( eLineEndFormat );
        }
        else
        {
            Reference< css::sdb::XColumn >  xField(m_pColumn->GetCurrentFieldValue());
            if (xField.is())
                aText = GetText(xField, m_pColumn->GetParent().getNumberFormatter());
        }
    }
    return aText;
}

OUString SAL_CALL FmXEditCell::getSelectedText()
{
    ::osl::MutexGuard aGuard( m_aMutex );

    OUString aText;
    if ( m_pEditImplementation )
    {
        LineEnd eLineEndFormat = m_pColumn ? getModelLineEndSetting( m_pColumn->getModel() ) : LINEEND_LF;
        aText = m_pEditImplementation->GetSelected( eLineEndFormat );
    }
    return aText;
}

void SAL_CALL FmXEditCell::setSelection( const css::awt::Selection& aSelection )
{
    ::osl::MutexGuard aGuard( m_aMutex );

    if ( m_pEditImplementation )
        m_pEditImplementation->SetSelection( Selection( aSelection.Min, aSelection.Max ) );
}

css::awt::Selection SAL_CALL FmXEditCell::getSelection()
{
    ::osl::MutexGuard aGuard( m_aMutex );

    Selection aSel;
    if ( m_pEditImplementation )
        aSel = m_pEditImplementation->GetSelection();

    return css::awt::Selection(aSel.Min(), aSel.Max());
}

sal_Bool SAL_CALL FmXEditCell::isEditable()
{
    ::osl::MutexGuard aGuard( m_aMutex );

    return m_pEditImplementation && !m_pEditImplementation->IsReadOnly() && m_pEditImplementation->GetControl().IsEnabled();
}

void SAL_CALL FmXEditCell::setEditable( sal_Bool bEditable )
{
    ::osl::MutexGuard aGuard( m_aMutex );

    if ( m_pEditImplementation )
        m_pEditImplementation->SetReadOnly( !bEditable );
}

sal_Int16 SAL_CALL FmXEditCell::getMaxTextLen()
{
    ::osl::MutexGuard aGuard( m_aMutex );

    return m_pEditImplementation ? m_pEditImplementation->GetMaxTextLen() : 0;
}

void SAL_CALL FmXEditCell::setMaxTextLen( sal_Int16 nLen )
{
    ::osl::MutexGuard aGuard( m_aMutex );

    if ( m_pEditImplementation )
        m_pEditImplementation->SetMaxTextLen( nLen );
}

void SAL_CALL FmXEditCell::addChangeListener( const Reference< form::XChangeListener >&&nbsp;Listener )
{
    m_aChangeListeners.addInterface( Listener );
}

void SAL_CALL FmXEditCell::removeChangeListener( const Reference< form::XChangeListener >& Listener )
{
    m_aChangeListeners.removeInterface( Listener );
}

void FmXEditCell::onTextChanged()
{
    css::awt::TextEvent aEvent;
    aEvent.Source = *this;
    m_aTextListeners.notifyEach( &awt::XTextListener::textChanged, aEvent );
}

void FmXEditCell::onFocusGained( const awt::FocusEvent& _rEvent )
{
    FmXTextCell::onFocusGained( _rEvent );
    m_sValueOnEnter = getText();
}

void FmXEditCell::onFocusLost( const awt::FocusEvent& _rEvent )
{
    FmXTextCell::onFocusLost( _rEvent );

    if ( getText() != m_sValueOnEnter )
    {
        lang::EventObject aEvent( *this );
        m_aChangeListeners.notifyEach( &XChangeListener::changed, aEvent );
    }
}

IMPL_LINK_NOARG(FmXEditCell, ModifyHdl, LinkParamNone*, void)
{
    if (m_aTextListeners.getLength())
        onTextChanged();
}

FmXCheckBoxCell::FmXCheckBoxCell( DbGridColumn* pColumn, std::unique_ptr<DbCellControl> pControl )
                :FmXDataCell( pColumn, std::move(pControl) )
                ,m_aItemListeners(m_aMutex)
                ,m_aActionListeners( m_aMutex )
                ,m_pBox( & static_cast< CheckBoxControl& >( m_pCellControl->GetWindow() ) )
{
    m_pBox->SetAuxModifyHdl(LINK(this, FmXCheckBoxCell, ModifyHdl));
}

FmXCheckBoxCell::~FmXCheckBoxCell()
{
    if (!OComponentHelper::rBHelper.bDisposed)
    {
        acquire();
        dispose();
    }
}

// OComponentHelper
void FmXCheckBoxCell::disposing()
{
    css::lang::EventObject aEvt(*this);
    m_aItemListeners.disposeAndClear(aEvt);
    m_aActionListeners.disposeAndClear(aEvt);

    m_pBox->SetToggleHdl(Link<weld::CheckButton&,void>());
    m_pBox = nullptr;

    FmXDataCell::disposing();
}


Any SAL_CALL FmXCheckBoxCell::queryAggregation( const css::uno::Type& _rType )
{
    Any aReturn = FmXDataCell::queryAggregation( _rType );

    if ( !aReturn.hasValue() )
        aReturn = FmXCheckBoxCell_Base::queryInterface( _rType );

    return aReturn;
}


Sequence< css::uno::Type > SAL_CALL FmXCheckBoxCell::getTypes(  )
{
    return ::comphelper::concatSequences(
        FmXDataCell::getTypes(),
        FmXCheckBoxCell_Base::getTypes()
    );
}


IMPLEMENT_GET_IMPLEMENTATION_ID( FmXCheckBoxCell )

void SAL_CALL FmXCheckBoxCell::addItemListener( const Reference< css::awt::XItemListener >& l )
{
    m_aItemListeners.addInterface( l );
}

void SAL_CALL FmXCheckBoxCell::removeItemListener( const Reference< css::awt::XItemListener >& l )
{
    m_aItemListeners.removeInterface( l );
}

void SAL_CALL FmXCheckBoxCell::setState( sal_Int16 n )
{
    ::osl::MutexGuard aGuard( m_aMutex );

    if (m_pBox)
    {
        UpdateFromColumn();
        m_pBox->SetState( static_cast<TriState>(n) );
    }
}

sal_Int16 SAL_CALL FmXCheckBoxCell::getState()
{
    ::osl::MutexGuard aGuard( m_aMutex );

    if (m_pBox)
    {
        UpdateFromColumn();
        return static_cast<sal_Int16>(m_pBox->GetState());
    }
    return TRISTATE_INDET;
}

void SAL_CALL FmXCheckBoxCell::enableTriState(sal_Bool b)
{
    ::osl::MutexGuard aGuard( m_aMutex );

    if (m_pBox)
        m_pBox->EnableTriState( b );
}

void SAL_CALL FmXCheckBoxCell::addActionListener( const Reference< awt::XActionListener >& Listener )
{
    m_aActionListeners.addInterface( Listener );
}


void SAL_CALL FmXCheckBoxCell::removeActionListener( const Reference< awt::XActionListener >& Listener )
{
    m_aActionListeners.removeInterface( Listener );
}

void SAL_CALL FmXCheckBoxCell::setLabel( const OUString& Label )
{
    SolarMutexGuard aGuard;
    if ( m_pColumn )
    {
        DbGridControl& rGrid( m_pColumn->GetParent() );
        rGrid.SetColumnTitle( rGrid.GetColumnId( m_pColumn->GetFieldPos() ), Label );
    }
}

void SAL_CALL FmXCheckBoxCell::setActionCommand( const OUString& Command )
{
    m_aActionCommand = Command;
}

IMPL_LINK_NOARG(FmXCheckBoxCell, ModifyHdl, LinkParamNone*, void)
{
    // check boxes are to be committed immediately (this holds for ordinary check box controls in
    // documents, and this must hold for check boxes in grid columns, too
    // 91210 - 22.08.2001 - frank.schoenheit@sun.com
    m_pCellControl->Commit();

    Reference< XWindow > xKeepAlive( this );
    if ( m_aItemListeners.getLength() && m_pBox )
    {
        awt::ItemEvent aEvent;
        aEvent.Source = *this;
        aEvent.Highlighted = 0;
        aEvent.Selected = m_pBox->GetState();
        m_aItemListeners.notifyEach( &awt::XItemListener::itemStateChanged, aEvent );
    }
    if ( m_aActionListeners.getLength() )
    {
        awt::ActionEvent aEvent;
        aEvent.Source = *this;
        aEvent.ActionCommand = m_aActionCommand;
        m_aActionListeners.notifyEach( &awt::XActionListener::actionPerformed, aEvent );
    }
}

FmXListBoxCell::FmXListBoxCell(DbGridColumn* pColumn, std::unique_ptr<DbCellControl> pControl)
  : FmXTextCell(pColumn, std::move(pControl))
  , m_aItemListeners(m_aMutex)
  , m_aActionListeners(m_aMutex)
  , m_pBox(&static_cast<svt::ListBoxControl&>(m_pCellControl->GetWindow()))
  , m_nLines(Application::GetSettings().GetStyleSettings().GetListBoxMaximumLineCount())
  , m_bMulti(false)
{
    m_pBox->SetAuxModifyHdl(LINK(this, FmXListBoxCell, ChangedHdl));
}

FmXListBoxCell::~FmXListBoxCell()
{
    if (!OComponentHelper::rBHelper.bDisposed)
    {
        acquire();
        dispose();
    }
}

// OComponentHelper
void FmXListBoxCell::disposing()
{
    css::lang::EventObject aEvt(*this);
    m_aItemListeners.disposeAndClear(aEvt);
    m_aActionListeners.disposeAndClear(aEvt);

    m_pBox->SetAuxModifyHdl(Link<bool,void>());
    m_pBox = nullptr;

    FmXTextCell::disposing();
}

Any SAL_CALL FmXListBoxCell::queryAggregation( const css::uno::Type& _rType )
{
    Any aReturn = FmXTextCell::queryAggregation(_rType);

    if ( !aReturn.hasValue() )
        aReturn = FmXListBoxCell_Base::queryInterface( _rType );

    return aReturn;
}

Sequence< css::uno::Type > SAL_CALL FmXListBoxCell::getTypes(  )
{
    return ::comphelper::concatSequences(
        FmXTextCell::getTypes(),
        FmXListBoxCell_Base::getTypes()
    );
}

IMPLEMENT_GET_IMPLEMENTATION_ID( FmXListBoxCell )

void SAL_CALL FmXListBoxCell::addItemListener(const Reference< css::awt::XItemListener >& l)
{
    m_aItemListeners.addInterface( l );
}

void SAL_CALL FmXListBoxCell::removeItemListener(const Reference< css::awt::XItemListener >& l)
{
    m_aItemListeners.removeInterface( l );
}

void SAL_CALL FmXListBoxCell::addActionListener(const Reference< css::awt::XActionListener >& l)
{
    m_aActionListeners.addInterface( l );
}

void SAL_CALL FmXListBoxCell::removeActionListener(const Reference< css::awt::XActionListener >& l)
{
    m_aActionListeners.removeInterface( l );
}

void SAL_CALL FmXListBoxCell::addItem(const OUString& aItem, sal_Int16 nPos)
{
    ::osl::MutexGuard aGuard( m_aMutex );
    if (m_pBox)
    {
        weld::ComboBox& rBox = m_pBox->get_widget();
        rBox.insert_text(nPos, aItem);
    }
}

void SAL_CALL FmXListBoxCell::addItems(const css::uno::Sequence<OUString>& aItems, sal_Int16 nPos)
{
    ::osl::MutexGuard aGuard( m_aMutex );
    if (m_pBox)
    {
        weld::ComboBox& rBox = m_pBox->get_widget();
        sal_uInt16 nP = nPos;
        for ( const auto& rItem : aItems )
        {
            rBox.insert_text(nP, rItem);
            if ( nPos != -1 )    // Not if 0xFFFF, because LIST_APPEND
                nP++;
        }
    }
}

void SAL_CALL FmXListBoxCell::removeItems(sal_Int16 nPos, sal_Int16 nCount)
{
    ::osl::MutexGuard aGuard( m_aMutex );
    if ( m_pBox )
    {
        weld::ComboBox& rBox = m_pBox->get_widget();
        for ( sal_uInt16 n = nCount; n; )
            rBox.remove( nPos + (--n) );
    }
}

sal_Int16 SAL_CALL FmXListBoxCell::getItemCount()
{
    ::osl::MutexGuard aGuard( m_aMutex );
    if (!m_pBox)
        return 0;
    weld::ComboBox& rBox = m_pBox->get_widget();
    return rBox.get_count();
}

OUString SAL_CALL FmXListBoxCell::getItem(sal_Int16 nPos)
{
    ::osl::MutexGuard aGuard( m_aMutex );
    if (!m_pBox)
        return OUString();
    weld::ComboBox& rBox = m_pBox->get_widget();
    return rBox.get_text(nPos);
}

css::uno::Sequence<OUString> SAL_CALL FmXListBoxCell::getItems()
{
    ::osl::MutexGuard aGuard( m_aMutex );

    css::uno::Sequence<OUString> aSeq;
    if (m_pBox)
    {
        weld::ComboBox& rBox = m_pBox->get_widget();
        const sal_Int32 nEntries = rBox.get_count();
        aSeq = css::uno::Sequence<OUString>( nEntries );
        for ( sal_Int32 n = nEntries; n; )
        {
            --n;
            aSeq.getArray()[n] = rBox.get_text( n );
        }
    }
    return aSeq;
}

sal_Int16 SAL_CALL FmXListBoxCell::getSelectedItemPos()
{
    ::osl::MutexGuard aGuard( m_aMutex );
    if (m_pBox)
    {
        UpdateFromColumn();
        weld::ComboBox& rBox = m_pBox->get_widget();
        int nPos = rBox.get_active();
        if (nPos == -1)
            return -1; // nothing selected
        if (nPos > SHRT_MAX || nPos < SHRT_MIN)
            throw std::out_of_range("awt::XListBox::getSelectedItemPos can only return a short");
        return nPos;
    }
    return -1; // nothing selected
}

Sequence< sal_Int16 > SAL_CALL FmXListBoxCell::getSelectedItemsPos()
{
    ::osl::MutexGuard aGuard( m_aMutex );

    if (m_pBox)
    {
        UpdateFromColumn();
        weld::ComboBox& rBox = m_pBox->get_widget();
        auto nActive = rBox.get_active();
        if (nActive != -1)
        {
            return { o3tl::narrowing<short>(nActive) };
        }
    }
    return {};
}

OUString SAL_CALL FmXListBoxCell::getSelectedItem()
{
    ::osl::MutexGuard aGuard( m_aMutex );

    OUString aItem;

    if (m_pBox)
    {
        UpdateFromColumn();
        weld::ComboBox& rBox = m_pBox->get_widget();
        aItem = rBox.get_active_text();
    }

    return aItem;
}

css::uno::Sequence<OUString> SAL_CALL FmXListBoxCell::getSelectedItems()
{
    ::osl::MutexGuard aGuard( m_aMutex );

    if (m_pBox)
    {
        UpdateFromColumn();
        weld::ComboBox& rBox = m_pBox->get_widget();
        auto nActive = rBox.get_active();
        if (nActive != -1)
        {
            return { rBox.get_text(nActive) };
        }
    }
    return {};
}

void SAL_CALL FmXListBoxCell::selectItemPos(sal_Int16 nPos, sal_Bool bSelect)
{
    ::osl::MutexGuard aGuard( m_aMutex );

    if (m_pBox)
    {
        weld::ComboBox& rBox = m_pBox->get_widget();
        if (bSelect)
            rBox.set_active(nPos);
        else if (nPos == rBox.get_active())
            rBox.set_active(-1);
    }
}

void SAL_CALL FmXListBoxCell::selectItemsPos(const Sequence< sal_Int16 >& aPositions, sal_Bool bSelect)
{
    ::osl::MutexGuard aGuard( m_aMutex );

    if (m_pBox)
    {
        weld::ComboBox& rBox = m_pBox->get_widget();
        for ( sal_uInt16 n = static_cast<sal_uInt16>(aPositions.getLength()); n; )
        {
            auto nPos = static_cast<sal_uInt16>(aPositions.getConstArray()[--n]);
            if (bSelect)
                rBox.set_active(nPos);
            else if (nPos == rBox.get_active())
                rBox.set_active(-1);
        }
    }
}

void SAL_CALL FmXListBoxCell::selectItem(const OUString& aItem, sal_Bool bSelect)
{
    ::osl::MutexGuard aGuard( m_aMutex );

    if (m_pBox)
    {
        weld::ComboBox& rBox = m_pBox->get_widget();
        auto nPos = rBox.find_text(aItem);
        if (bSelect)
            rBox.set_active(nPos);
        else if (nPos == rBox.get_active())
            rBox.set_active(-1);
    }
}

sal_Bool SAL_CALL FmXListBoxCell::isMutipleMode()
{
    ::osl::MutexGuard aGuard( m_aMutex );

    return m_bMulti;
}

void SAL_CALL FmXListBoxCell::setMultipleMode(sal_Bool bMulti)
{
    ::osl::MutexGuard aGuard( m_aMutex );

    m_bMulti = bMulti;
}

sal_Int16 SAL_CALL FmXListBoxCell::getDropDownLineCount()
{
    ::osl::MutexGuard aGuard( m_aMutex );
    return m_nLines;
}

void SAL_CALL FmXListBoxCell::setDropDownLineCount(sal_Int16 nLines)
{
    ::osl::MutexGuard aGuard( m_aMutex );

    m_nLines = nLines; // just store it to return it
}

void SAL_CALL FmXListBoxCell::makeVisible(sal_Int16 /*nEntry*/)
{
}

IMPL_LINK(FmXListBoxCell, ChangedHdl, bool, bInteractive, void)
{
    if (!m_pBox)
        return;

    weld::ComboBox& rBox = m_pBox->get_widget();

    if (bInteractive && !rBox.changed_by_direct_pick())
        return;

    OnDoubleClick();

    css::awt::ItemEvent aEvent;
    aEvent.Source = *this;
    aEvent.Highlighted = 0;

    // with multiple selection 0xFFFF, otherwise the ID
    aEvent.Selected = (rBox.get_active() != -1 )
                    ? rBox.get_active() : 0xFFFF;

    m_aItemListeners.notifyEach( &awt::XItemListener::itemStateChanged, aEvent );
}

void FmXListBoxCell::OnDoubleClick()
{
    css::awt::ActionEvent aEvent;
    aEvent.Source = *this;
    weld::ComboBox& rBox = m_pBox->get_widget();
    aEvent.ActionCommand = rBox.get_active_text();

    m_aActionListeners.notifyEach( &css::awt::XActionListener::actionPerformed, aEvent );
}

FmXComboBoxCell::FmXComboBoxCell( DbGridColumn* pColumn, std::unique_ptr<DbCellControl> pControl )
    :FmXTextCell( pColumn, std::move(pControl) )
    ,m_aItemListeners( m_aMutex )
    ,m_aActionListeners( m_aMutex )
    ,m_pComboBox(&static_cast<ComboBoxControl&>(m_pCellControl->GetWindow()))
    ,m_nLines(Application::GetSettings().GetStyleSettings().GetListBoxMaximumLineCount())
{
    m_pComboBox->SetAuxModifyHdl(LINK(this, FmXComboBoxCell, ChangedHdl));
}

FmXComboBoxCell::~FmXComboBoxCell()
{
    if ( !OComponentHelper::rBHelper.bDisposed )
    {
        acquire();
        dispose();
    }

}

void FmXComboBoxCell::disposing()
{
    css::lang::EventObject aEvt(*this);
    m_aItemListeners.disposeAndClear(aEvt);
    m_aActionListeners.disposeAndClear(aEvt);

    m_pComboBox->SetAuxModifyHdl(Link<bool,void>());
    m_pComboBox = nullptr;

    FmXTextCell::disposing();
}

Any SAL_CALL FmXComboBoxCell::queryAggregation( const css::uno::Type& _rType )
{
    Any aReturn = FmXTextCell::queryAggregation(_rType);

    if ( !aReturn.hasValue() )
        aReturn = FmXComboBoxCell_Base::queryInterface( _rType );

    return aReturn;
}

Sequence< Type > SAL_CALL FmXComboBoxCell::getTypes(  )
{
    return ::comphelper::concatSequences(
        FmXTextCell::getTypes(),
        FmXComboBoxCell_Base::getTypes()
    );
}

IMPLEMENT_GET_IMPLEMENTATION_ID( FmXComboBoxCell )

void SAL_CALL FmXComboBoxCell::addItemListener(const Reference< awt::XItemListener >&&nbsp;l)
{
    m_aItemListeners.addInterface( l );
}

void SAL_CALL FmXComboBoxCell::removeItemListener(const Reference< awt::XItemListener >&&nbsp;l)
{
    m_aItemListeners.removeInterface( l );
}

void SAL_CALL FmXComboBoxCell::addActionListener(const Reference< awt::XActionListener >& l)
{
    m_aActionListeners.addInterface( l );
}


void SAL_CALL FmXComboBoxCell::removeActionListener(const Reference< awt::XActionListener >& l)
{
    m_aActionListeners.removeInterface( l );
}

void SAL_CALL FmXComboBoxCell::addItem( const OUString& Item, sal_Int16 Pos )
{
    ::osl::MutexGuard aGuard( m_aMutex );
    if (!m_pComboBox)
        return;
    weld::ComboBox& rBox = m_pComboBox->get_widget();
    rBox.insert_text(Pos, Item);
}

void SAL_CALL FmXComboBoxCell::addItems( const Sequence< OUString >& Items, sal_Int16 Pos )
{
    ::osl::MutexGuard aGuard( m_aMutex );
    if (!m_pComboBox)
        return;
    weld::ComboBox& rBox = m_pComboBox->get_widget();
    sal_uInt16 nP = Pos;
    for ( const auto& rItem : Items )
    {
        rBox.insert_text(nP, rItem);
        if ( Pos != -1 )
            nP++;
    }
}

void SAL_CALL FmXComboBoxCell::removeItems( sal_Int16 Pos, sal_Int16 Count )
{
    ::osl::MutexGuard aGuard( m_aMutex );
    if (!m_pComboBox)
        return;
    weld::ComboBox& rBox = m_pComboBox->get_widget();
    for ( sal_uInt16 n = Count; n; )
        rBox.remove( Pos + (--n) );
}

sal_Int16 SAL_CALL FmXComboBoxCell::getItemCount()
{
    ::osl::MutexGuard aGuard( m_aMutex );
    if (!m_pComboBox)
        return 0;
    weld::ComboBox& rBox = m_pComboBox->get_widget();
    return rBox.get_count();
}

OUString SAL_CALL FmXComboBoxCell::getItem( sal_Int16 Pos )
{
    ::osl::MutexGuard aGuard( m_aMutex );
    if (!m_pComboBox)
        return OUString();
    weld::ComboBox& rBox = m_pComboBox->get_widget();
    return rBox.get_text(Pos);
}

Sequence< OUString > SAL_CALL FmXComboBoxCell::getItems()
{
    ::osl::MutexGuard aGuard( m_aMutex );

    Sequence< OUString > aItems;
    if (m_pComboBox)
    {
        weld::ComboBox& rBox = m_pComboBox->get_widget();
        const sal_Int32 nEntries = rBox.get_count();
        aItems.realloc( nEntries );
        OUString* pItem = aItems.getArray();
        for ( sal_Int32 n=0; n<nEntries; ++n, ++pItem )
            *pItem = rBox.get_text(n);
    }
    return aItems;
}

sal_Int16 SAL_CALL FmXComboBoxCell::getDropDownLineCount()
{
    ::osl::MutexGuard aGuard( m_aMutex );
    return m_nLines;
}

void SAL_CALL FmXComboBoxCell::setDropDownLineCount(sal_Int16 nLines)
{
    ::osl::MutexGuard aGuard( m_aMutex );
    m_nLines = nLines; // just store it to return it
}

IMPL_LINK(FmXComboBoxCell, ChangedHdl, bool, bInteractive, void)
{
    if (!m_pComboBox)
        return;

    weld::ComboBox& rComboBox = m_pComboBox->get_widget();

    if (bInteractive && !rComboBox.changed_by_direct_pick())
        return;

    awt::ItemEvent aEvent;
    aEvent.Source = *this;
    aEvent.Highlighted = 0;

    // with invalid selection 0xFFFF, otherwise the position
    aEvent.Selected =   ( rComboBox.get_active() != -1 )
                    ?   rComboBox.get_active()
                    :   0xFFFF;
    m_aItemListeners.notifyEach( &awt::XItemListener::itemStateChanged, aEvent );
}

FmXFilterCell::FmXFilterCell(DbGridColumn* pColumn, std::unique_ptr<DbFilterField> pControl )
              :FmXGridCell( pColumn, std::move(pControl) )
              ,m_aTextListeners(m_aMutex)
{
    static_cast<DbFilterField*>(m_pCellControl.get())->SetCommitHdl( LINK( this, FmXFilterCell, OnCommit ) );
}

FmXFilterCell::~FmXFilterCell()
{
    if (!OComponentHelper::rBHelper.bDisposed)
    {
        acquire();
        dispose();
    }

}

void FmXFilterCell::PaintCell( OutputDevice& rDev, const tools::Rectangle& rRect )
{
    static_cast< DbFilterField* >( m_pCellControl.get() )->PaintCell( rDev, rRect );
}

// OComponentHelper

void FmXFilterCell::disposing()
{
    css::lang::EventObject aEvt(*this);
    m_aTextListeners.disposeAndClear(aEvt);

    static_cast<DbFilterField*>(m_pCellControl.get())->SetCommitHdl(Link<DbFilterField&,an style='color:red'>void>());

    FmXGridCell::disposing();
}


Any SAL_CALL FmXFilterCell::queryAggregation( const css::uno::Type& _rType )
{
    Any aReturn = FmXGridCell::queryAggregation(_rType);

    if ( !aReturn.hasValue() )
        aReturn = FmXFilterCell_Base::queryInterface( _rType );

    return aReturn;
}


Sequence< css::uno::Type > SAL_CALL FmXFilterCell::getTypes(  )
{
    return ::comphelper::concatSequences(
        FmXGridCell::getTypes(),
        FmXFilterCell_Base::getTypes()
    );
}


IMPLEMENT_GET_IMPLEMENTATION_ID( FmXFilterCell )

// css::awt::XTextComponent

void SAL_CALL FmXFilterCell::addTextListener(const Reference< css::awt::XTextListener >&&nbsp;l)
{
    m_aTextListeners.addInterface( l );
}


void SAL_CALL FmXFilterCell::removeTextListener(const Reference< css::awt::XTextListener >& l)
{
    m_aTextListeners.removeInterface( l );
}

void SAL_CALL FmXFilterCell::setText( const OUString& aText )
{
    ::osl::MutexGuard aGuard( m_aMutex );
    static_cast<DbFilterField*>(m_pCellControl.get())->SetText(aText);
}

void SAL_CALL FmXFilterCell::insertText( const css::awt::Selection& /*rSel*/, const OUString& /*aText*/ )
{
}

OUString SAL_CALL FmXFilterCell::getText()
{
    ::osl::MutexGuard aGuard( m_aMutex );
    return static_cast<DbFilterField*>(m_pCellControl.get())->GetText();
}

OUString SAL_CALL FmXFilterCell::getSelectedText()
{
    return getText();
}

void SAL_CALL FmXFilterCell::setSelection( const css::awt::Selection& /*aSelection*/ )
{
}

css::awt::Selection SAL_CALL FmXFilterCell::getSelection()
{
    return css::awt::Selection();
}

sal_Bool SAL_CALL FmXFilterCell::isEditable()
{
    return true;
}

void SAL_CALL FmXFilterCell::setEditable( sal_Bool /*bEditable*/ )
{
}

sal_Int16 SAL_CALL FmXFilterCell::getMaxTextLen()
{
    return 0;
}

void SAL_CALL FmXFilterCell::setMaxTextLen( sal_Int16 /*nLen*/ )
{
}

IMPL_LINK_NOARG(FmXFilterCell, OnCommit, DbFilterField&, void)
{
    css::awt::TextEvent aEvt;
    aEvt.Source = *this;
    m_aTextListeners.notifyEach( &css::awt::XTextListener::textChanged, aEvt );
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Messung V0.5 in Prozent
C=94 H=96 G=94

¤ Dauer der Verarbeitung: 0.77 Sekunden  (vorverarbeitet am  2026-05-08) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.