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  

Impressum 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""_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
--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=95 H=99 G=96

¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.25Angebot  Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können  ¤

*Eine klare Vorstellung vom Zielzustand






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.