/* -*- 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 <core_resource.hxx>
#include <FieldDescControl.hxx>
#include <FieldControls.hxx>
#include <comphelper/diagnose_ex.hxx>
#include <TableDesignHelpBar.hxx>
#include <vcl/svapp.hxx>
#include <FieldDescriptions.hxx>
#include <svl/numuno.hxx>
#include <vcl/transfer.hxx>
#include <com/sun/star/sdbc/ColumnValue.hpp>
#include <com/sun/star/util/NumberFormat.hpp>
#include <com/sun/star/util/XNumberFormatPreviewer.hpp>
#include <com/sun/star/util/XNumberFormatTypes.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <QEnumTypes.hxx>
#include <helpids.h>
#include <connectivity/dbtools.hxx>
#include <connectivity/dbconversion.hxx>
#include <comphelper/numbers.hxx>
#include <comphelper/types.hxx>
#include <UITools.hxx>
#include <strings.hrc>
#include <osl/diagnose.h>

using namespace dbaui;
using namespace dbtools;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::beans;
using namespace ::com::sun::star::lang;
using namespace ::com::sun::star::sdbc;
using namespace ::com::sun::star::util;

namespace
{
    template< typename T1, typename T2> void lcl_HideAndDeleteControl(short& _nPos,std::unique_ptr<T1>& _pControl, std::unique_ptr<T2>& _pControlText)
    {
        if ( _pControl )
        {
            --_nPos;
            _pControl->hide();
            _pControlText->hide();
            _pControl.reset();
            _pControlText.reset();
        }
    }
}

OFieldDescControl::OFieldDescControl(weld::Container* pPage, OTableDesignHelpBar* pHelpBar)
    : m_xBuilder(Application::CreateBuilder(pPage, u"dbaccess/ui/fielddescpage.ui"_ustr))
    , m_xContainer(m_xBuilder->weld_container(u"FieldDescPage"_ustr))
    , m_pHelp( pHelpBar )
    , m_pLastFocusWindow(nullptr)
    , m_pActFocusWindow(nullptr)
    , m_nPos(-1)
    , aYes(DBA_RES(STR_VALUE_YES))
    , aNo(DBA_RES(STR_VALUE_NO))
    , m_nEditWidth(50)
    , pActFieldDescr(nullptr)
{
    if (m_pHelp)
        m_pHelp->connect_focus_out(LINK(this, OFieldDescControl, HelpFocusOut));
}

OFieldDescControl::~OFieldDescControl()
{
    dispose();
}

void OFieldDescControl::dispose()
{
    // Destroy children
    DeactivateAggregate( tpDefault );
    DeactivateAggregate( tpRequired );
    DeactivateAggregate( tpTextLen );
    DeactivateAggregate( tpNumType );
    DeactivateAggregate( tpScale );
    DeactivateAggregate( tpLength );
    DeactivateAggregate( tpFormat );
    DeactivateAggregate( tpAutoIncrement );
    DeactivateAggregate( tpBoolDefault );
    DeactivateAggregate( tpColumnName );
    DeactivateAggregate( tpType );
    DeactivateAggregate( tpAutoIncrementValue );
    m_pHelp = nullptr;
    m_pLastFocusWindow = nullptr;
    m_pActFocusWindow = nullptr;
    m_xDefaultText.reset();
    m_xRequiredText.reset();
    m_xAutoIncrementText.reset();
    m_xTextLenText.reset();
    m_xNumTypeText.reset();
    m_xLengthText.reset();
    m_xScaleText.reset();
    m_xFormatText.reset();
    m_xBoolDefaultText.reset();
    m_xColumnNameText.reset();
    m_xTypeText.reset();
    m_xAutoIncrementValueText.reset();
    m_xRequired.reset();
    m_xNumType.reset();
    m_xAutoIncrement.reset();
    m_xDefault.reset();
    m_xTextLen.reset();
    m_xLength.reset();
    m_xScale.reset();
    m_xFormatSample.reset();
    m_xBoolDefault.reset();
    m_xColumnName.reset();
    m_xType.reset();
    m_xAutoIncrementValue.reset();
    m_xFormat.reset();
    m_xContainer.reset();
    m_xBuilder.reset();
}

OUString OFieldDescControl::BoolStringPersistent(std::u16string_view rUIString) const
{
    if (rUIString == aNo)
        return OUString('0');
    if (rUIString == aYes)
        return OUString('1');
    return OUString();
}

OUString OFieldDescControl::BoolStringUI(const OUString& rPersistentString) const
{
    // Older versions may store a language dependent string as a default
    if (rPersistentString == aYes || rPersistentString == aNo)
        return rPersistentString;

    if (rPersistentString == "0")
        return aNo;
    if (rPersistentString == "1")
        return aYes;

    return DBA_RES(STR_VALUE_NONE);
}

void OFieldDescControl::Init()
{
    Reference< css::util::XNumberFormatter > xFormatter = GetFormatter();
    ::dbaui::setEvalDateFormatForFormatter(xFormatter);
}

void OFieldDescControl::SetReadOnly( bool bReadOnly )
{
    // Enable/disable Controls
    struct final
    {
        OWidgetBase * aggregate;
        weld::Widget * text;
    } const aggregates[] = {
        {m_xRequired.get(), m_xRequiredText.get()}
        , {m_xNumType.get(), m_xNumTypeText.get()}
        , {m_xAutoIncrement.get(), m_xAutoIncrementText.get()}
        , {m_xDefault.get(), m_xDefaultText.get()}
        , {m_xTextLen.get(), m_xTextLenText.get()}
        , {m_xLength.get(), m_xLengthText.get()}
        , {m_xScale.get(), m_xScaleText.get()}
        , {m_xColumnName.get(), m_xColumnNameText.get()}
        , {m_xType.get(), m_xTypeText.get()}
        , {m_xAutoIncrementValue.get(), m_xAutoIncrementValueText.get()}};

    for (auto const & aggregate: aggregates)
    {
        if (aggregate.text)
            aggregate.text->set_sensitive(!bReadOnly);
        if (aggregate.aggregate)
            aggregate.aggregate->set_sensitive(!bReadOnly);
    }

    if (m_xFormat)
    {
        assert(m_xFormatText);
        m_xFormat->set_sensitive(!bReadOnly);
        m_xFormatText->set_sensitive(!bReadOnly);
    }
}

void OFieldDescControl::SetControlText( sal_uInt16 nControlId, const OUString& rText )
{
    // Set the Controls' texts
    switch( nControlId )
    {
        case FIELD_PROPERTY_BOOL_DEFAULT:
            if (m_xBoolDefault)
            {
                OUString sOld = m_xBoolDefault->get_active_text();
                m_xBoolDefault->set_active_text(rText);
                if (sOld != rText)
                    ChangeHdl(m_xBoolDefault->GetComboBox());
            }
            break;
        case FIELD_PROPERTY_DEFAULT:
            if (m_xDefault)
            {
                m_xDefault->set_text(rText);
                UpdateFormatSample(pActFieldDescr);
            }
            break;

        case FIELD_PROPERTY_REQUIRED:
            if (m_xRequired)
                m_xRequired->set_active_text(rText);
            break;

        case FIELD_PROPERTY_TEXTLEN:
            if (m_xTextLen)
                m_xTextLen->set_text(rText);
            break;

        case FIELD_PROPERTY_NUMTYPE:
            if (m_xNumType)
                m_xNumType->set_active_text(rText);
            break;

        case FIELD_PROPERTY_AUTOINC:
            if (m_xAutoIncrement)
            {
                OUString sOld = m_xAutoIncrement->get_active_text();
                m_xAutoIncrement->set_active_text(rText);
                if (sOld != rText)
                    ChangeHdl(m_xAutoIncrement->GetComboBox());
            }
            break;

        case FIELD_PROPERTY_LENGTH:
            if (m_xLength)
                m_xLength->set_text(rText);
            break;

        case FIELD_PROPERTY_SCALE:
            if (m_xScale)
                m_xScale->set_text(rText);
            break;

        case FIELD_PROPERTY_FORMAT:
            if (pActFieldDescr)
                UpdateFormatSample(pActFieldDescr);
            break;
        case FIELD_PROPERTY_COLUMNNAME:
            if (m_xColumnName)
                m_xColumnName->set_text(rText);
            break;
        case FIELD_PROPERTY_TYPE:
            if (m_xType)
                m_xType->set_active_text(rText);
            break;
        case FIELD_PROPERTY_AUTOINCREMENT:
            if (m_xAutoIncrementValue)
                m_xAutoIncrementValue->set_text(rText);
            break;
    }
}

IMPL_LINK_NOARG(OFieldDescControl, FormatClickHdl, weld::Button&, void)
{
    // Create temporary Column, which is used for data exchange with Dialog
    if( !pActFieldDescr )
        return;

    sal_Int32 nOldFormatKey(pActFieldDescr->GetFormatKey());
    SvxCellHorJustify rOldJustify = pActFieldDescr->GetHorJustify();
    Reference< XNumberFormatsSupplier >  xSupplier = GetFormatter()->getNumberFormatsSupplier();
    SvNumberFormatsSupplierObj* pSupplierImpl = comphelper::getFromUnoTunnel<SvNumberFormatsSupplierObj>( xSupplier );
    if (!pSupplierImpl)
        return;

    SvNumberFormatter* pFormatter = pSupplierImpl->GetNumberFormatter();
    if(!::dbaui::callColumnFormatDialog(m_xContainer.get(),pFormatter,pActFieldDescr->GetType(),nOldFormatKey,rOldJustify,true))
        return;

    bool bModified = false;
    if(nOldFormatKey != pActFieldDescr->GetFormatKey())
    {
        pActFieldDescr->SetFormatKey( nOldFormatKey );
        bModified = true;
    }
    if(rOldJustify != pActFieldDescr->GetHorJustify())
    {
        pActFieldDescr->SetHorJustify( rOldJustify );
        bModified = true;
    }

    if(bModified)
    {
        SetModified(true);
        UpdateFormatSample(pActFieldDescr);
    }
}

void OFieldDescControl::SetModified(bool /*bModified*/)
{
}

IMPL_LINK(OFieldDescControl, ChangeHdl, weld::ComboBox&, rListBox, void)
{
    if (!pActFieldDescr)
        return;

    if (rListBox.get_value_changed_from_saved())
        SetModified(true);

    // Special treatment for Bool fields
    if (m_xRequired && &rListBox == m_xRequired->GetWidget() && m_xBoolDefault)
    {
        // If m_xRequired = sal_True then the sal_Bool field must NOT contain <<none>>
        OUString sDef = BoolStringUI(::comphelper::getString(pActFieldDescr->GetControlDefault()));

        if (m_xRequired->get_active() == 0) // Yes
        {
            m_xBoolDefault->remove_text(DBA_RES(STR_VALUE_NONE));
            if (sDef != aYes && sDef != aNo)
                m_xBoolDefault->set_active(1);  // No as a default
            else
                m_xBoolDefault->set_active_text(sDef);
        }
        else if (m_xBoolDefault->get_count() < 3)
        {
            m_xBoolDefault->append_text(DBA_RES(STR_VALUE_NONE));
            m_xBoolDefault->set_active_text(sDef);
        }
    }

    // A special treatment only for AutoIncrement
    if (m_xAutoIncrement && &rListBox == m_xAutoIncrement->GetWidget())
    {
        if (rListBox.get_active() == 1)
        { // no
            DeactivateAggregate( tpAutoIncrementValue );
            if(pActFieldDescr->IsPrimaryKey())
                DeactivateAggregate( tpRequired );
            else if( pActFieldDescr->getTypeInfo()->bNullable )
            {
                ActivateAggregate( tpRequired );
                if (m_xRequired)
                {
                    if( pActFieldDescr->IsNullable() )
                        m_xRequired->set_active(1); // no
                    else
                        m_xRequired->set_active(0); // yes
                }
            }
            ActivateAggregate( tpDefault );
        }
        else
        {
            DeactivateAggregate( tpRequired );
            DeactivateAggregate( tpDefault );
            ActivateAggregate( tpAutoIncrementValue );
        }
    }

    if (m_xType && &rListBox == m_xType->GetWidget())
    {
        TOTypeInfoSP pTypeInfo = getTypeInfo(m_xType->get_active());
        pActFieldDescr->FillFromTypeInfo(pTypeInfo,true,false); // SetType(pTypeInfo);

        DisplayData(pActFieldDescr);
        CellModified(-1, m_xType->GetPos());
    }
}

void OFieldDescControl::ActivateAggregate( EControlType eType )
{
    // Create Controls
    switch( eType )
    {
    case tpDefault:
        if (m_xDefault)
            return;
        m_nPos++;
        m_xDefaultText = m_xBuilder->weld_label(u"DefaultValueText"_ustr);
        m_xDefaultText->show();
        m_xDefault = std::make_unique<OPropEditCtrl>(
                m_xBuilder->weld_entry(u"DefaultValue"_ustr), STR_HELP_DEFAULT_VALUE, FIELD_PROPERTY_DEFAULT);
        InitializeControl(m_xDefault->GetWidget(),HID_TAB_ENT_DEFAULT);
        m_xDefault->show();
        break;
    case tpAutoIncrementValue:
        if (m_xAutoIncrementValue || !isAutoIncrementValueEnabled())
            return;
        m_nPos++;
        m_xAutoIncrementValueText = m_xBuilder->weld_label(u"AutoIncrementValueText"_ustr);
        m_xAutoIncrementValueText->show();
        m_xAutoIncrementValue = std::make_unique<OPropEditCtrl>(
                m_xBuilder->weld_spin_button(u"AutoIncrementValue"_ustr), STR_HELP_AUTOINCREMENT_VALUE,
                FIELD_PROPERTY_AUTOINCREMENT);
        m_xAutoIncrementValue->set_text( getAutoIncrementValue() );
        InitializeControl(m_xAutoIncrementValue->GetWidget(),HID_TAB_AUTOINCREMENTVALUE);
        m_xAutoIncrementValue->show();
        break;

    case tpRequired:
    {
        if (m_xRequired)
            return;
        Reference< XDatabaseMetaData> xMetaData = getMetaData();

        if(xMetaData.is() && xMetaData->supportsNonNullableColumns())
        {
            m_nPos++;
            m_xRequiredText = m_xBuilder->weld_label(u"RequiredText"_ustr);
            m_xRequiredText->show();
            m_xRequired = std::make_unique<OPropListBoxCtrl>(
                    m_xBuilder->weld_combo_box(u"Required"_ustr), STR_HELP_AUTOINCREMENT_VALUE,
                    FIELD_PROPERTY_AUTOINCREMENT);
            m_xRequired->append_text(aYes);
            m_xRequired->append_text(aNo);
            m_xRequired->set_active(1);

            InitializeControl(m_xRequired.get(),HID_TAB_ENT_REQUIRED, true);
            m_xRequired->show();
        }
    }
    break;
    case tpAutoIncrement:
    {
        if (m_xAutoIncrement)
            return;
        m_nPos++;
        m_xAutoIncrementText = m_xBuilder->weld_label(u"AutoIncrementText"_ustr);
        m_xAutoIncrementText->show();
        m_xAutoIncrement = std::make_unique<OPropListBoxCtrl>(
                m_xBuilder->weld_combo_box(u"AutoIncrement"_ustr), STR_HELP_AUTOINCREMENT,
                FIELD_PROPERTY_AUTOINC);
        m_xAutoIncrement->append_text(aYes);
        m_xAutoIncrement->append_text(aNo);
        m_xAutoIncrement->set_active(0);
        InitializeControl(m_xAutoIncrement.get(),HID_TAB_ENT_AUTOINCREMENT, true);
        m_xAutoIncrement->show();
    }
    break;
    case tpTextLen:
        if (m_xTextLen)
            return;
        m_nPos++;
        m_xTextLenText = m_xBuilder->weld_label(u"TextLengthText"_ustr);
        m_xTextLenText->show();
        m_xTextLen = CreateNumericControl(u"TextLength"_ustr, STR_HELP_TEXT_LENGTH, FIELD_PROPERTY_TEXTLEN,HID_TAB_ENT_TEXT_LEN);
        break;

    case tpType:
        if (m_xType)
            return;
        m_nPos++;
        m_xTypeText = m_xBuilder->weld_label(u"TypeText"_ustr);
        m_xTypeText->show();
        m_xType = std::make_unique<OPropListBoxCtrl>(
                m_xBuilder->weld_combo_box(u"Type"_ustr), STR_HELP_AUTOINCREMENT, FIELD_PROPERTY_TYPE);
        {
            const OTypeInfoMap* pTypeInfo = getTypeInfo();
            for (auto const& elem : *pTypeInfo)
                m_xType->append_text(elem.second->aUIName);
        }
        m_xType->set_active(0);
        InitializeControl(m_xType.get(),HID_TAB_ENT_TYPE, true);
        m_xType->show();
        break;
    case tpColumnName:
        if (m_xColumnName)
            return;
        m_nPos++;
        {
            sal_Int32 nMax(0);
            OUString aTmpString;
            try
            {
                Reference< XDatabaseMetaData> xMetaData = getMetaData();
                if ( xMetaData.is() )
                {
                    nMax =  xMetaData->getMaxColumnNameLength();
                    aTmpString = xMetaData->getExtraNameCharacters();
                }
            }
            catch (const Exception&)
            {
                DBG_UNHANDLED_EXCEPTION("dbaccess");
            }
            m_xColumnNameText = m_xBuilder->weld_label(u"ColumnNameText"_ustr);
            m_xColumnNameText->show();
            m_xColumnName = std::make_unique<OPropColumnEditCtrl>(
                    m_xBuilder->weld_entry(u"ColumnName"_ustr), aTmpString,
                    STR_HELP_DEFAULT_VALUE, FIELD_PROPERTY_COLUMNNAME);
            m_xColumnName->set_max_length(nMax);
            m_xColumnName->setCheck( isSQL92CheckEnabled(getConnection()) );
        }

        InitializeControl(m_xColumnName->GetWidget(),HID_TAB_ENT_COLUMNNAME);
        m_xColumnName->show();
        break;
    case tpNumType:
        if (m_xNumType)
            return;
        m_nPos++;
        m_xNumTypeText = m_xBuilder->weld_label(u"NumTypeText"_ustr);
        m_xNumTypeText->show();
        m_xNumType = std::make_unique<OPropListBoxCtrl>(
                m_xBuilder->weld_combo_box(u"NumType"_ustr), STR_HELP_NUMERIC_TYPE, FIELD_PROPERTY_NUMTYPE);
        m_xNumType->append_text(u"Byte"_ustr);
        m_xNumType->append_text(u"SmallInt"_ustr);
        m_xNumType->append_text(u"Integer"_ustr);
        m_xNumType->append_text(u"Single"_ustr);
        m_xNumType->append_text(u"Double"_ustr);
        m_xNumType->set_active(2);
        InitializeControl(m_xNumType.get(),HID_TAB_ENT_NUMTYP, true);
        m_xNumType->show();
        break;

    case tpLength:
        if (m_xLength)
            return;
        m_nPos++;
        m_xLengthText = m_xBuilder->weld_label(u"LengthText"_ustr);
        m_xLengthText->show();
        m_xLength = CreateNumericControl(u"Length"_ustr, STR_HELP_LENGTH, FIELD_PROPERTY_LENGTH,HID_TAB_ENT_LEN);
        break;

    case tpScale:
        if (m_xScale)
            return;
        m_nPos++;
        m_xScaleText = m_xBuilder->weld_label(u"ScaleText"_ustr);
        m_xScaleText->show();
        m_xScale = CreateNumericControl(u"Scale"_ustr, STR_HELP_SCALE, FIELD_PROPERTY_SCALE,HID_TAB_ENT_SCALE);
        break;

    case tpFormat:
        if (!m_xFormat)
        {
            m_nPos++;
            m_xFormatText = m_xBuilder->weld_label(u"FormatTextText"_ustr);
            m_xFormatText->show();

            m_xFormatSample = std::make_unique<OPropEditCtrl>(
                    m_xBuilder->weld_entry(u"FormatText"_ustr), STR_HELP_FORMAT_CODE, -1);
            m_xFormatSample->set_editable(false);
            m_xFormatSample->set_sensitive(false);
            InitializeControl(m_xFormatSample->GetWidget(),HID_TAB_ENT_FORMAT_SAMPLE);
            m_xFormatSample->show();

            m_xFormat = m_xBuilder->weld_button(u"FormatButton"_ustr);
            m_xFormat->connect_clicked( LINK( this, OFieldDescControl, FormatClickHdl ) );
            InitializeControl(m_xFormat.get(),HID_TAB_ENT_FORMAT);
            m_xFormat->show();
        }

        UpdateFormatSample(pActFieldDescr);
        break;
    case tpBoolDefault:
        if (m_xBoolDefault)
            return;

        m_nPos++;
        m_xBoolDefaultText = m_xBuilder->weld_label(u"BoolDefaultText"_ustr);
        m_xBoolDefaultText->show();
        m_xBoolDefault = std::make_unique<OPropListBoxCtrl>(
                m_xBuilder->weld_combo_box(u"BoolDefault"_ustr), STR_HELP_BOOL_DEFAULT,
                FIELD_PROPERTY_BOOL_DEFAULT);
        m_xBoolDefault->append_text(DBA_RES(STR_VALUE_NONE));
        m_xBoolDefault->append_text(aYes);
        m_xBoolDefault->append_text(aNo);
        InitializeControl(m_xBoolDefault->GetWidget(),HID_TAB_ENT_BOOL_DEFAULT);
        m_xBoolDefault->show();
        break;
    }
}

void OFieldDescControl::InitializeControl(OPropListBoxCtrl* _pControl,const OUString& _sHelpId,bool _bAddChangeHandler)
{
    if ( _bAddChangeHandler )
        _pControl->GetComboBox().connect_changed(LINK(this,OFieldDescControl,ChangeHdl));

    InitializeControl(_pControl->GetWidget(), _sHelpId);
}

void OFieldDescControl::InitializeControl(weld::Widget* pControl,const OUString& _sHelpId)
{
    pControl->set_help_id(_sHelpId);
    pControl->connect_focus_in(LINK(this, OFieldDescControl, OnControlFocusGot));
    pControl->connect_focus_out(LINK(this, OFieldDescControl, OnControlFocusLost));

    if (dynamic_cast<weld::Entry*>(pControl))
    {
        int nWidthRequest = Application::GetDefaultDevice()->LogicToPixel(Size(m_nEditWidth, 0), MapMode(MapUnit::MapAppFont)).Width();
        pControl->set_size_request(nWidthRequest, -1);
    }
}

std::unique_ptr<OPropNumericEditCtrl> OFieldDescControl::CreateNumericControl(const OUString& rId, TranslateId pHelpId, short _nProperty, const OUString& _sHelpId)
{
    auto xControl = std::make_unique<OPropNumericEditCtrl>(
            m_xBuilder->weld_spin_button(rId), pHelpId, _nProperty);
    xControl->set_digits(0);
    xControl->set_range(0, 0x7FFFFFFF);   // Should be changed outside, if needed
    xControl->show();

    InitializeControl(xControl->GetWidget(),_sHelpId);

    return xControl;
}

void OFieldDescControl::DeactivateAggregate( EControlType eType )
{
    m_pLastFocusWindow = nullptr;
    // Destroy Controls
    switch( eType )
    {
    case tpDefault:
        lcl_HideAndDeleteControl(m_nPos,m_xDefault,m_xDefaultText);
        break;

    case tpAutoIncrementValue:
        lcl_HideAndDeleteControl(m_nPos,m_xAutoIncrementValue,m_xAutoIncrementValueText);
        break;

    case tpColumnName:
        lcl_HideAndDeleteControl(m_nPos,m_xColumnName,m_xColumnNameText);
        break;

    case tpType:
        lcl_HideAndDeleteControl(m_nPos,m_xType,m_xTypeText);
        break;

    case tpAutoIncrement:
        lcl_HideAndDeleteControl(m_nPos,m_xAutoIncrement,m_xAutoIncrementText);
        break;

    case tpRequired:
        lcl_HideAndDeleteControl(m_nPos,m_xRequired,m_xRequiredText);
        break;

    case tpTextLen:
        lcl_HideAndDeleteControl(m_nPos,m_xTextLen,m_xTextLenText);
        break;

    case tpNumType:
        lcl_HideAndDeleteControl(m_nPos,m_xNumType,m_xNumTypeText);
        break;

    case tpLength:
        lcl_HideAndDeleteControl(m_nPos,m_xLength,m_xLengthText);
        break;

    case tpScale:
        lcl_HideAndDeleteControl(m_nPos,m_xScale,m_xScaleText);
        break;

    case tpFormat:
        // TODO: we have to check if we have to increment m_nPos again
        lcl_HideAndDeleteControl(m_nPos,m_xFormat,m_xFormatText);
        if (m_xFormatSample)
        {
            m_xFormatSample->hide();
            m_xFormatSample.reset();
        }
        break;
    case tpBoolDefault:
        lcl_HideAndDeleteControl(m_nPos,m_xBoolDefault,m_xBoolDefaultText);
        break;
    }
}

void OFieldDescControl::DisplayData(OFieldDescription* pFieldDescr )
{
    pActFieldDescr = pFieldDescr;
    if(!pFieldDescr)
    {
        if (m_pHelp)
            m_pHelp->SetHelpText( OUString() );
        DeactivateAggregate( tpDefault );
        DeactivateAggregate( tpRequired );
        DeactivateAggregate( tpTextLen );
        DeactivateAggregate( tpNumType );
        DeactivateAggregate( tpScale );
        DeactivateAggregate( tpLength );
        DeactivateAggregate( tpFormat );
        DeactivateAggregate( tpAutoIncrement );
        DeactivateAggregate( tpBoolDefault );
        DeactivateAggregate( tpColumnName );
        DeactivateAggregate( tpType );
        DeactivateAggregate( tpAutoIncrementValue );
        m_pPreviousType = TOTypeInfoSP();
        // Reset the saved focus' pointer
        m_pLastFocusWindow = nullptr;
        return;
    }

    TOTypeInfoSP pFieldType(pFieldDescr->getTypeInfo());

    ActivateAggregate( tpColumnName );
    ActivateAggregate( tpType );

    OSL_ENSURE(pFieldType,"We need a type information here!");
    // If the type has changed, substitute Controls
    if( m_pPreviousType != pFieldType )
    {
        // Reset the saved focus' pointer
        m_pLastFocusWindow = nullptr;

        // Controls, which must NOT be displayed again
        DeactivateAggregate( tpNumType );

        // determine which controls we should show and which not

        // 1. the required control
        if ( pFieldType->bNullable )
            ActivateAggregate( tpRequired );
        else
            DeactivateAggregate( tpRequired );

        // 2. the autoincrement
        if ( pFieldType->bAutoIncrement )
        {
            DeactivateAggregate( tpRequired );
            DeactivateAggregate( tpDefault );
            ActivateAggregate( tpAutoIncrement );
            ActivateAggregate( tpAutoIncrementValue );
        }
        else
        {
            DeactivateAggregate( tpAutoIncrement );
            DeactivateAggregate( tpAutoIncrementValue );
            if(pFieldType->bNullable)
                ActivateAggregate( tpRequired );
            else
                DeactivateAggregate( tpRequired );
            ActivateAggregate( tpDefault );
        }
        // 3. the scale and precision
        if (pFieldType->nPrecision)
        {
            ActivateAggregate( tpLength );
            m_xLength->set_max(std::max<sal_Int32>(pFieldType->nPrecision,pFieldDescr->GetPrecision()));
            m_xLength->set_editable(!pFieldType->aCreateParams.isEmpty());
        }
        else
            DeactivateAggregate( tpLength );

        if (pFieldType->nMaximumScale)
        {
            ActivateAggregate( tpScale );
            m_xScale->set_range(pFieldType->nMinimumScale,
                                std::max<sal_Int32>(pFieldType->nMaximumScale,pFieldDescr->GetScale()));
            m_xScale->set_editable(!pFieldType->aCreateParams.isEmpty() && pFieldType->aCreateParams != "PRECISION");
        }
        else
            DeactivateAggregate( tpScale );

        // and now look for type specific things
        switch( pFieldType->nType )
        {
            case DataType::CHAR:
            case DataType::VARCHAR:
            case DataType::LONGVARCHAR:
                DeactivateAggregate( tpLength );
                DeactivateAggregate( tpBoolDefault );

                ActivateAggregate( tpDefault );
                ActivateAggregate( tpFormat );
                if (pFieldType->nPrecision)
                {
                    ActivateAggregate( tpTextLen );
                    m_xTextLen->set_max(std::max<sal_Int32>(pFieldType->nPrecision,pFieldDescr->GetPrecision()));
                    m_xTextLen->set_editable(!pFieldType->aCreateParams.isEmpty());
                }
                else
                    DeactivateAggregate( tpTextLen );
                break;
            case DataType::DATE:
            case DataType::TIME:
            case DataType::TIMESTAMP:
            case DataType::TIME_WITH_TIMEZONE:
            case DataType::TIMESTAMP_WITH_TIMEZONE:
                DeactivateAggregate( tpLength ); // we don't need a length for date types
                DeactivateAggregate( tpTextLen );
                DeactivateAggregate( tpBoolDefault );

                ActivateAggregate( tpDefault );
                ActivateAggregate( tpFormat );
                break;
            case DataType::BIT:
                if ( !pFieldType->aCreateParams.isEmpty() )
                {
                    DeactivateAggregate( tpFormat );
                    DeactivateAggregate( tpTextLen );
                    DeactivateAggregate( tpBoolDefault );
                    break;
                }
                [[fallthrough]];
            case DataType::BOOLEAN:
                DeactivateAggregate( tpTextLen );
                DeactivateAggregate( tpFormat );
                DeactivateAggregate( tpDefault );

                ActivateAggregate( tpBoolDefault );
                break;
            case DataType::DECIMAL:
            case DataType::NUMERIC:
            case DataType::BIGINT:
            case DataType::FLOAT:
            case DataType::DOUBLE:
            case DataType::TINYINT:
            case DataType::SMALLINT:
            case DataType::INTEGER:
            case DataType::REAL:
                DeactivateAggregate( tpTextLen );
                DeactivateAggregate( tpBoolDefault );

                ActivateAggregate( tpFormat );
                break;
            case DataType::BINARY:
            case DataType::VARBINARY:
                DeactivateAggregate( tpDefault );
                DeactivateAggregate( tpRequired );
                DeactivateAggregate( tpTextLen );
                DeactivateAggregate( tpBoolDefault );

                ActivateAggregate( tpFormat );
                break;
            case DataType::LONGVARBINARY:
            case DataType::SQLNULL:
            case DataType::OBJECT:
            case DataType::DISTINCT:
            case DataType::STRUCT:
            case DataType::ARRAY:
            case DataType::BLOB:
            case DataType::CLOB:
            case DataType::REF:
            case DataType::OTHER:
                DeactivateAggregate( tpFormat );
                DeactivateAggregate( tpTextLen );
                DeactivateAggregate( tpBoolDefault );

                break;
            default:
                OSL_FAIL("Unknown type");
        }
        m_pPreviousType = pFieldType;
    }

    if (pFieldDescr->IsPrimaryKey())
    {
        DeactivateAggregate(tpRequired);
    }
    else if (!m_xAutoIncrement && pFieldType)
    {
        if (pFieldType->bNullable)
            ActivateAggregate(tpRequired);
        else
            DeactivateAggregate(tpRequired);
    }
    // Initialize Controls
    if (m_xAutoIncrement)
    {
        if ( pFieldDescr->IsAutoIncrement() )
        {
            m_xAutoIncrement->set_active(0); // yes
            ActivateAggregate( tpAutoIncrementValue );
            if (m_xAutoIncrementValue)
                m_xAutoIncrementValue->set_text(pFieldDescr->GetAutoIncrementValue());
            DeactivateAggregate( tpRequired );
            DeactivateAggregate( tpDefault );
        }
        else
        {
            // disable autoincrement value because it should only be visible when autoincrement is to true
            DeactivateAggregate( tpAutoIncrementValue );
            m_xAutoIncrement->set_active(1);        // no
            ActivateAggregate( tpDefault );
            // Affects pRequired
            if(!pFieldDescr->IsPrimaryKey())
                ActivateAggregate( tpRequired );
        }
    }

    if (m_xDefault)
    {
        m_xDefault->set_text(getControlDefault(pFieldDescr));
        m_xDefault->save_value();
    }

    if (m_xBoolDefault)
    {
        // If m_xRequired = sal_True then the sal_Bool field must NOT contain <<none>>
        OUString sValue;
        pFieldDescr->GetControlDefault() >>= sValue;
        OUString sDef = BoolStringUI(sValue);

        // Make sure that <<none>> is only present if the field can be NULL
        if ( ( pFieldType && !pFieldType->bNullable ) || !pFieldDescr->IsNullable() )
        {
            pFieldDescr->SetIsNullable(ColumnValue::NO_NULLS); // The type says so

            m_xBoolDefault->remove_text(DBA_RES(STR_VALUE_NONE));
            if ( sDef != aYes && sDef != aNo )
                m_xBoolDefault->set_active(1);  // No as a default
            else
                m_xBoolDefault->set_active_text(sDef);

            pFieldDescr->SetControlDefault(Any(BoolStringPersistent(m_xBoolDefault->get_active_text())));
        }
        else if (m_xBoolDefault->get_count() < 3)
        {
            m_xBoolDefault->append_text(DBA_RES(STR_VALUE_NONE));
            m_xBoolDefault->set_active_text(sDef);
        }
        else
            m_xBoolDefault->set_active_text(sDef);
    }

    if (m_xRequired)
    {
        if( pFieldDescr->IsNullable() )
            m_xRequired->set_active(1); // no
        else
            m_xRequired->set_active(0); // yes
    }

    if (m_xTextLen)
    {
        m_xTextLen->set_text(OUString::number(pFieldDescr->GetPrecision()));
        m_xTextLen->save_value();
    }

    if( m_xNumType )
    {
        OSL_FAIL("OFieldDescControl::DisplayData: invalid num type!");
    }

    if (m_xLength)
        m_xLength->set_text(OUString::number(pFieldDescr->GetPrecision()));

    if (m_xScale)
        m_xScale->set_text(OUString::number(pFieldDescr->GetScale()));

    if (m_xFormat)
        UpdateFormatSample(pFieldDescr);

    if (m_xColumnName)
        m_xColumnName->set_text(pFieldDescr->GetName());

    if (m_xType)
    {
        sal_Int32 nPos = pFieldType ? m_xType->find_text(pFieldDescr->getTypeInfo()->aUIName) : -1;
        if (nPos == -1)
        {
            const OTypeInfoMap* pMap = getTypeInfo();
            OTypeInfoMap::const_iterator aIter = pMap->find(pFieldType ? pFieldDescr->getTypeInfo()->nType : pFieldDescr->GetType());
            if(aIter == pMap->end() && !pMap->empty())
            {
                aIter = pMap->begin();
                if(pFieldDescr->GetPrecision() > aIter->second->nPrecision)
                    pFieldDescr->SetPrecision(aIter->second->nPrecision);
                if(pFieldDescr->GetScale() > aIter->second->nMaximumScale)
                    pFieldDescr->SetScale(0);
                if(!aIter->second->bNullable && pFieldDescr->IsNullable())
                    pFieldDescr->SetIsNullable(ColumnValue::NO_NULLS);
                if(!aIter->second->bAutoIncrement && pFieldDescr->IsAutoIncrement())
                    pFieldDescr->SetAutoIncrement(false);
            }
            if ( aIter != pMap->end() )
            {
                pFieldDescr->SetType(aIter->second);
            }
        }
        m_xType->set_active_text(pFieldDescr->getTypeInfo()->aUIName);
    }

    // Enable/disable Controls
    bool bRead(IsReadOnly());

    SetReadOnly( bRead );
}

IMPL_LINK(OFieldDescControl, OnControlFocusGot, weld::Widget&, rControl, void )
{
    OUString strHelpText;

    if (m_xTextLen && &rControl == m_xTextLen->GetWidget())
    {
        m_xTextLen->save_value();
        strHelpText = m_xTextLen->GetHelp();
    }
    else if (m_xLength && &rControl == m_xLength->GetWidget())
    {
        m_xLength->save_value();
        strHelpText = m_xLength->GetHelp();
    }
    else if (m_xScale && &rControl == m_xScale->GetWidget())
    {
        m_xScale->save_value();
        strHelpText = m_xScale->GetHelp();
    }
    else if (m_xColumnName && &rControl == m_xColumnName->GetWidget())
    {
        m_xColumnName->save_value();
        strHelpText = m_xColumnName->GetHelp();
    }
    else if (m_xDefault && &rControl == m_xDefault->GetWidget())
    {
        m_xDefault->save_value();
        strHelpText = m_xDefault->GetHelp();
    }
    else if (m_xFormatSample && &rControl == m_xFormatSample->GetWidget())
    {
        m_xFormatSample->save_value();
        strHelpText = m_xFormatSample->GetHelp();
    }
    else if (m_xAutoIncrementValue && &rControl == m_xAutoIncrementValue->GetWidget())
    {
        m_xAutoIncrementValue->save_value();
        strHelpText = m_xAutoIncrementValue->GetHelp();
    }
    else if (m_xRequired && &rControl == m_xRequired->GetWidget())
    {
        m_xRequired->save_value();
        strHelpText = m_xRequired->GetHelp();
    }
    else if (m_xNumType && &rControl == m_xNumType->GetWidget())
    {
        m_xNumType->save_value();
        strHelpText = m_xNumType->GetHelp();
    }
    else if (m_xAutoIncrement && &rControl == m_xAutoIncrement->GetWidget())
    {
        m_xAutoIncrement->save_value();
        strHelpText = m_xAutoIncrement->GetHelp();
    }
    else if (m_xBoolDefault && &rControl == m_xBoolDefault->GetWidget())
    {
        m_xBoolDefault->save_value();
        strHelpText = m_xBoolDefault->GetHelp();
    }
    else if (m_xType && &rControl == m_xType->GetWidget())
    {
        m_xType->save_value();
        strHelpText = m_xType->GetHelp();
    }
    else if (m_xFormat && &rControl == m_xFormat.get())
        strHelpText = DBA_RES(STR_HELP_FORMAT_BUTTON);

    if (!strHelpText.isEmpty() && m_pHelp)
        m_pHelp->SetHelpText(strHelpText);

    m_pActFocusWindow = &rControl;

    m_aControlFocusIn.Call(rControl);
}

IMPL_LINK(OFieldDescControl, OnControlFocusLost, weld::Widget&, rControl, void )
{
    if (m_xLength && &rControl == m_xLength->GetWidget() && m_xLength->get_value_changed_from_saved())
        CellModified(-1, m_xLength->GetPos());
    else if (m_xTextLen && &rControl == m_xTextLen->GetWidget() && m_xTextLen->get_value_changed_from_saved())
        CellModified(-1, m_xTextLen->GetPos());
    else if (m_xScale && &rControl == m_xScale->GetWidget() && m_xScale->get_value_changed_from_saved())
        CellModified(-1, m_xScale->GetPos());
    else if (m_xColumnName && &rControl == m_xColumnName->GetWidget() && m_xColumnName->get_value_changed_from_saved())
        CellModified(-1, m_xColumnName->GetPos());
    else if (m_xDefault && &rControl == m_xDefault->GetWidget() && m_xDefault->get_value_changed_from_saved())
        CellModified(-1, m_xDefault->GetPos());
    else if (m_xFormatSample && &rControl == m_xFormatSample->GetWidget() && m_xFormatSample->get_value_changed_from_saved())
        CellModified(-1, m_xFormatSample->GetPos());
    else if (m_xAutoIncrementValue && &rControl == m_xAutoIncrementValue->GetWidget() && m_xAutoIncrementValue->get_value_changed_from_saved())
        CellModified(-1, m_xAutoIncrementValue->GetPos());
    else if (m_xRequired && &rControl == m_xRequired->GetWidget() && m_xRequired->get_value_changed_from_saved())
        CellModified(-1, m_xRequired->GetPos());
    else if (m_xNumType && &rControl == m_xNumType->GetWidget() && m_xNumType->get_value_changed_from_saved())
        CellModified(-1, m_xNumType->GetPos());
    else if (m_xAutoIncrement && &rControl == m_xAutoIncrement->GetWidget() && m_xAutoIncrement->get_value_changed_from_saved())
        CellModified(-1, m_xAutoIncrement->GetPos());
    else if (m_xBoolDefault && &rControl == m_xBoolDefault->GetWidget() && m_xBoolDefault->get_value_changed_from_saved())
        CellModified(-1, m_xBoolDefault->GetPos());
    else if (m_xType && &rControl == m_xType->GetWidget() && m_xType->get_value_changed_from_saved())
        CellModified(-1, m_xType->GetPos());
    else if (m_xDefault && &rControl == m_xDefault->GetWidget())
        UpdateFormatSample(pActFieldDescr);

    implFocusLost(&rControl);
}

void OFieldDescControl::SaveData( OFieldDescription* pFieldDescr )
{
    if( !pFieldDescr )
        return;

    // Read out Controls
    OUString sDefault;
    if (m_xDefault)
    {
        // tdf#138409 take the control default in the UI Locale format, e.g. 12,34 and return a string
        // suitable as the database default, e.g. 12.34
        sDefault = CanonicalizeToControlDefault(pFieldDescr, m_xDefault->get_text());
    }
    else if (m_xBoolDefault)
    {
        sDefault = BoolStringPersistent(m_xBoolDefault->get_active_text());
    }

    if ( !sDefault.isEmpty() )
        pFieldDescr->SetControlDefault(Any(sDefault));
    else
        pFieldDescr->SetControlDefault(Any());

    if((m_xRequired && m_xRequired->get_active() == 0) || pFieldDescr->IsPrimaryKey() || (m_xBoolDefault && m_xBoolDefault->get_count() == 2))  // yes
        pFieldDescr->SetIsNullable( ColumnValue::NO_NULLS );
    else
        pFieldDescr->SetIsNullable( ColumnValue::NULLABLE );

    if (m_xAutoIncrement)
        pFieldDescr->SetAutoIncrement(m_xAutoIncrement->get_active() == 0);

    if( m_xTextLen )
        pFieldDescr->SetPrecision( static_cast<sal_Int32>(m_xTextLen->get_value()) );
    else if (m_xLength)
        pFieldDescr->SetPrecision( static_cast<sal_Int32>(m_xLength->get_value()) );
    if (m_xScale)
        pFieldDescr->SetScale( static_cast<sal_Int32>(m_xScale->get_value()) );

    if (m_xColumnName)
        pFieldDescr->SetName(m_xColumnName->get_text());

    if (m_xAutoIncrementValue && isAutoIncrementValueEnabled())
        pFieldDescr->SetAutoIncrementValue(m_xAutoIncrementValue->get_text());
}

void OFieldDescControl::UpdateFormatSample(OFieldDescription const * pFieldDescr)
{
    if (pFieldDescr && m_xFormatSample)
        m_xFormatSample->set_text(getControlDefault(pFieldDescr,false));
}

void OFieldDescControl::GrabFocus()
{
    m_xContainer->grab_focus();

    // Set the Focus to the Control that has been active last
    if (m_pLastFocusWindow)
    {
        m_pLastFocusWindow->grab_focus();
        m_pLastFocusWindow = nullptr;
    }
}

void OFieldDescControl::implFocusLost(weld::Widget* _pWhich)
{
    // Remember the active Control
    if (!m_pLastFocusWindow)
        m_pLastFocusWindow = _pWhich;

    // Reset HelpText
    if (m_pHelp && !m_pHelp->HasFocus())
        m_pHelp->SetHelpText( OUString() );
}

IMPL_LINK_NOARG(OFieldDescControl, HelpFocusOut, weld::Widget&, void)
{
    m_pHelp->SetHelpText(OUString());
}

bool OFieldDescControl::IsFocusInEditableWidget() const
{
    if (m_xDefault && m_pActFocusWindow == m_xDefault->GetWidget())
        return true;
    if (m_xFormatSample && m_pActFocusWindow == m_xFormatSample->GetWidget())
        return true;
    if (m_xTextLen && m_pActFocusWindow == m_xTextLen->GetWidget())
        return true;
    if (m_xLength && m_pActFocusWindow == m_xLength->GetWidget())
        return true;
    if (m_xScale && m_pActFocusWindow == m_xScale->GetWidget())
        return true;
    if (m_xColumnName && m_pActFocusWindow == m_xColumnName->GetWidget())
        return true;
    if (m_xAutoIncrementValue && m_pActFocusWindow == m_xAutoIncrementValue->GetWidget())
        return true;
    return false;
}

bool OFieldDescControl::HasChildPathFocus() const
{
    return m_xContainer && m_xContainer->has_child_focus();
}

bool OFieldDescControl::isCopyAllowed()
{
    int nStartPos, nEndPos;
    bool bAllowed = (m_pActFocusWindow != nullptr) && IsFocusInEditableWidget() &&
                        dynamic_cast<weld::Entry&>(*m_pActFocusWindow).get_selection_bounds(nStartPos, nEndPos);
    return bAllowed;
}

bool OFieldDescControl::isCutAllowed()
{
    int nStartPos, nEndPos;
    bool bAllowed = (m_pActFocusWindow != nullptr) && IsFocusInEditableWidget() &&
                        dynamic_cast<weld::Entry&>(*m_pActFocusWindow).get_selection_bounds(nStartPos, nEndPos);
    return bAllowed;
}

bool OFieldDescControl::isPasteAllowed()
{
    bool bAllowed = (m_pActFocusWindow != nullptr) && IsFocusInEditableWidget();
    if ( bAllowed )
    {
        TransferableDataHelper aTransferData(TransferableDataHelper::CreateFromClipboard(m_pActFocusWindow->get_clipboard()));
        bAllowed = aTransferData.HasFormat(SotClipboardFormatId::STRING);
    }
    return bAllowed;
}

void OFieldDescControl::cut()
{
    if (isCutAllowed())
        dynamic_cast<weld::Entry&>(*m_pActFocusWindow).cut_clipboard();
}

void OFieldDescControl::copy()
{
    if (isCopyAllowed()) // this only checks if the focus window is valid
        dynamic_cast<weld::Entry&>(*m_pActFocusWindow).copy_clipboard();
}

void OFieldDescControl::paste()
{
    if (m_pActFocusWindow) // this only checks if the focus window is valid
        dynamic_cast<weld::Entry&>(*m_pActFocusWindow).paste_clipboard();
}

bool OFieldDescControl::isTextFormat(const OFieldDescription* _pFieldDescr, sal_uInt32& _nFormatKey) const
{
    _nFormatKey = _pFieldDescr->GetFormatKey();
    bool bTextFormat = true;

    try
    {
        if (!_nFormatKey)
        {
            Reference< css::util::XNumberFormatTypes> xNumberTypes(GetFormatter()->getNumberFormatsSupplier()->getNumberFormats(),UNO_QUERY);
            OSL_ENSURE(xNumberTypes.is(),"XNumberFormatTypes is null!");

            _nFormatKey = ::dbtools::getDefaultNumberFormat( _pFieldDescr->GetType(),
                _pFieldDescr->GetScale(),
                _pFieldDescr->IsCurrency(),
                xNumberTypes,
                GetLocale());
        }
        sal_Int32 nNumberFormat = ::comphelper::getNumberFormatType(GetFormatter(),_nFormatKey);
        bTextFormat = (nNumberFormat == css::util::NumberFormat::TEXT);
    }
    catch(const Exception&)
    {

    }

    return bTextFormat;
}

OUString OFieldDescControl::getControlDefault( const OFieldDescription* _pFieldDescr, bool _bCheck) const
{
    OUString sDefault;
    bool bCheck = !_bCheck || _pFieldDescr->GetControlDefault().hasValue();
    if ( bCheck )
    {
        try
        {
            double nValue = 0.0;
            sal_uInt32 nFormatKey;
            bool bTextFormat = isTextFormat(_pFieldDescr,nFormatKey);
            if ( _pFieldDescr->GetControlDefault() >>= sDefault )
            {
                if ( !bTextFormat )
                {
                    if ( !sDefault.isEmpty() )
                    {
                        // The number will have been canonicalized with OUString::number in
                        // CanonicalizeToControlDefault so here we want to do the opposite in order
                        // to get a number to format
                        nValue = sDefault.toDouble();
                    }
                }
            }
            else
                _pFieldDescr->GetControlDefault() >>= nValue;

            Reference< css::util::XNumberFormatter> xNumberFormatter = GetFormatter();
            Reference<XPropertySet> xFormSet = xNumberFormatter->getNumberFormatsSupplier()->getNumberFormats()->getByKey(nFormatKey);
            OSL_ENSURE(xFormSet.is(),"XPropertySet is null!");
            OUString sFormat;
            xFormSet->getPropertyValue(u"FormatString"_ustr) >>= sFormat;

            if ( !bTextFormat )
            {
                Locale aLocale;
                ::comphelper::getNumberFormatProperty(xNumberFormatter,nFormatKey,u"Locale"_ustr) >>= aLocale;

                sal_Int32 nNumberFormat = ::comphelper::getNumberFormatType(xNumberFormatter,nFormatKey);
                if(     (nNumberFormat & css::util::NumberFormat::DATE)    == css::util::NumberFormat::DATE
                    || (nNumberFormat & css::util::NumberFormat::DATETIME) == css::util::NumberFormat::DATETIME )
                {
                    bool bDoCorrect = true;
                    if (!sDefault.isEmpty())
                    {
                        // nValue was converted from that string. If that string was a date, nValue
                        // is already in the required epoch, and we should not try to correct it
                        sal_Int32 nFormatKeyOf_sDefault = xNumberFormatter->detectNumberFormat(nFormatKey, sDefault);
                        sal_Int16 nNumberFormatType = comphelper::getNumberFormatType(xNumberFormatter, nFormatKeyOf_sDefault);
                        bDoCorrect = (nNumberFormatType & css::util::NumberFormat::DATE) == 0;
                    }
                    if (bDoCorrect)
                        nValue = DBTypeConversion::toNullDate(DBTypeConversion::getNULLDate(xNumberFormatter->getNumberFormatsSupplier()),nValue);
                }

                Reference< css::util::XNumberFormatPreviewer> xPreviewer(xNumberFormatter,UNO_QUERY);
                OSL_ENSURE(xPreviewer.is(),"XNumberFormatPreviewer is null!");
                sDefault = xPreviewer->convertNumberToPreviewString(sFormat,nValue,aLocale,true);
            }
            else if ( !(_bCheck && sDefault.isEmpty()) )
                sDefault = xNumberFormatter->formatString(nFormatKey, sDefault.isEmpty() ? sFormat : sDefault);
        }
        catch(const Exception&)
        {

        }
    }

    return sDefault;
}

// tdf#138409 intended to be effectively the reverse of getControlDefault to
// turn a user's possibly 12,34 format into 12.34 format for numerical types
OUString OFieldDescControl::CanonicalizeToControlDefault(const OFieldDescription* pFieldDescr, const OUString& rDefault) const
{
    if (rDefault.isEmpty())
        return rDefault;

    bool bIsNumericalType = false;
    switch (pFieldDescr->GetType())
    {
        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:
            bIsNumericalType = true;
            break;
    }

    if (!bIsNumericalType)
        return rDefault;

    try
    {
        sal_uInt32 nFormatKey;
        bool bTextFormat = isTextFormat(pFieldDescr, nFormatKey);
        if (bTextFormat)
            return rDefault;
        double nValue = GetFormatter()->convertStringToNumber(nFormatKey, rDefault);
        return OUString::number(nValue);
    }
    catch(const Exception&)
    {
    }

    return rDefault;
}


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