diff options
Diffstat (limited to 'dbaccess/source/ui/tabledesign')
-rw-r--r-- | dbaccess/source/ui/tabledesign/FieldDescriptions.cxx | 639 | ||||
-rw-r--r-- | dbaccess/source/ui/tabledesign/TEditControl.cxx | 1679 | ||||
-rw-r--r-- | dbaccess/source/ui/tabledesign/TEditControl.hxx | 204 | ||||
-rw-r--r-- | dbaccess/source/ui/tabledesign/TableController.cxx | 1495 | ||||
-rw-r--r-- | dbaccess/source/ui/tabledesign/TableDesignControl.cxx | 172 | ||||
-rw-r--r-- | dbaccess/source/ui/tabledesign/TableDesignHelpBar.cxx | 62 | ||||
-rw-r--r-- | dbaccess/source/ui/tabledesign/TableDesignView.cxx | 260 | ||||
-rw-r--r-- | dbaccess/source/ui/tabledesign/TableFieldControl.cxx | 154 | ||||
-rw-r--r-- | dbaccess/source/ui/tabledesign/TableFieldControl.hxx | 66 | ||||
-rw-r--r-- | dbaccess/source/ui/tabledesign/TableFieldDescWin.cxx | 140 | ||||
-rw-r--r-- | dbaccess/source/ui/tabledesign/TableFieldDescWin.hxx | 91 | ||||
-rw-r--r-- | dbaccess/source/ui/tabledesign/TableRow.cxx | 183 | ||||
-rw-r--r-- | dbaccess/source/ui/tabledesign/TableRowExchange.cxx | 67 | ||||
-rw-r--r-- | dbaccess/source/ui/tabledesign/TableUndo.cxx | 352 | ||||
-rw-r--r-- | dbaccess/source/ui/tabledesign/TableUndo.hxx | 136 |
15 files changed, 5700 insertions, 0 deletions
diff --git a/dbaccess/source/ui/tabledesign/FieldDescriptions.cxx b/dbaccess/source/ui/tabledesign/FieldDescriptions.cxx new file mode 100644 index 000000000..d8dce84a0 --- /dev/null +++ b/dbaccess/source/ui/tabledesign/FieldDescriptions.cxx @@ -0,0 +1,639 @@ +/* -*- 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 <FieldDescriptions.hxx> +#include <tools/diagnose_ex.h> +#include <strings.hxx> +#include <com/sun/star/sdbc/ColumnValue.hpp> +#include <comphelper/types.hxx> +#include <comphelper/extract.hxx> +#include <UITools.hxx> +#include <com/sun/star/util/NumberFormat.hpp> + +#define DEFAULT_VARCHAR_PRECISION 100 +#define DEFAULT_OTHER_PRECISION 16 +#define DEFAULT_NUMERIC_PRECISION 5 +#define DEFAULT_NUMERIC_SCALE 0 + +using namespace dbaui; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::util; + +OFieldDescription::OFieldDescription() + :m_nType(DataType::VARCHAR) + ,m_nPrecision(0) + ,m_nScale(0) + ,m_nIsNullable(ColumnValue::NULLABLE) + ,m_nFormatKey(0) + ,m_eHorJustify(SvxCellHorJustify::Standard) + ,m_bIsAutoIncrement(false) + ,m_bIsPrimaryKey(false) + ,m_bIsCurrency(false) + ,m_bHidden(false) +{ +} + +OFieldDescription::OFieldDescription( const OFieldDescription& rDescr ) + :m_aControlDefault(rDescr.m_aControlDefault) + ,m_aWidth(rDescr.m_aWidth) + ,m_aRelativePosition(rDescr.m_aRelativePosition) + ,m_pType(rDescr.m_pType) + ,m_xDest(rDescr.m_xDest) + ,m_xDestInfo(rDescr.m_xDestInfo) + ,m_sName(rDescr.m_sName) + ,m_sTypeName(rDescr.m_sTypeName) + ,m_sDescription(rDescr.m_sDescription) + ,m_sAutoIncrementValue(rDescr.m_sAutoIncrementValue) + ,m_nType(rDescr.m_nType) + ,m_nPrecision(rDescr.m_nPrecision) + ,m_nScale(rDescr.m_nScale) + ,m_nIsNullable(rDescr.m_nIsNullable) + ,m_nFormatKey(rDescr.m_nFormatKey) + ,m_eHorJustify(rDescr.m_eHorJustify) + ,m_bIsAutoIncrement(rDescr.m_bIsAutoIncrement) + ,m_bIsPrimaryKey(rDescr.m_bIsPrimaryKey) + ,m_bIsCurrency(rDescr.m_bIsCurrency) + ,m_bHidden(rDescr.m_bHidden) +{ +} + +OFieldDescription::~OFieldDescription() +{ +} + +OFieldDescription::OFieldDescription(const Reference< XPropertySet >& xAffectedCol,bool _bUseAsDest) + :m_nType(DataType::VARCHAR) + ,m_nPrecision(0) + ,m_nScale(0) + ,m_nIsNullable(ColumnValue::NULLABLE) + ,m_nFormatKey(0) + ,m_eHorJustify(SvxCellHorJustify::Standard) + ,m_bIsAutoIncrement(false) + ,m_bIsPrimaryKey(false) + ,m_bIsCurrency(false) + ,m_bHidden(false) +{ + OSL_ENSURE(xAffectedCol.is(),"PropertySet can not be null!"); + if ( !xAffectedCol.is() ) + return; + + if ( _bUseAsDest ) + { + m_xDest = xAffectedCol; + m_xDestInfo = xAffectedCol->getPropertySetInfo(); + } + else + { + try + { + Reference<XPropertySetInfo> xPropSetInfo = xAffectedCol->getPropertySetInfo(); + if(xPropSetInfo->hasPropertyByName(PROPERTY_NAME)) + SetName(::comphelper::getString(xAffectedCol->getPropertyValue(PROPERTY_NAME))); + if(xPropSetInfo->hasPropertyByName(PROPERTY_DESCRIPTION)) + SetDescription(::comphelper::getString(xAffectedCol->getPropertyValue(PROPERTY_DESCRIPTION))); + if(xPropSetInfo->hasPropertyByName(PROPERTY_HELPTEXT)) + { + OUString sHelpText; + xAffectedCol->getPropertyValue(PROPERTY_HELPTEXT) >>= sHelpText; + SetHelpText(sHelpText); + } + if(xPropSetInfo->hasPropertyByName(PROPERTY_DEFAULTVALUE)) + SetDefaultValue( xAffectedCol->getPropertyValue(PROPERTY_DEFAULTVALUE) ); + + if(xPropSetInfo->hasPropertyByName(PROPERTY_CONTROLDEFAULT)) + SetControlDefault( xAffectedCol->getPropertyValue(PROPERTY_CONTROLDEFAULT) ); + + if(xPropSetInfo->hasPropertyByName(PROPERTY_AUTOINCREMENTCREATION)) + SetAutoIncrementValue(::comphelper::getString(xAffectedCol->getPropertyValue(PROPERTY_AUTOINCREMENTCREATION))); + if(xPropSetInfo->hasPropertyByName(PROPERTY_TYPE)) + SetTypeValue(::comphelper::getINT32(xAffectedCol->getPropertyValue(PROPERTY_TYPE))); + if (xPropSetInfo->hasPropertyByName(PROPERTY_TYPENAME)) + SetTypeName(::comphelper::getString(xAffectedCol->getPropertyValue(PROPERTY_TYPENAME))); + if(xPropSetInfo->hasPropertyByName(PROPERTY_PRECISION)) + SetPrecision(::comphelper::getINT32(xAffectedCol->getPropertyValue(PROPERTY_PRECISION))); + if(xPropSetInfo->hasPropertyByName(PROPERTY_SCALE)) + SetScale(::comphelper::getINT32(xAffectedCol->getPropertyValue(PROPERTY_SCALE))); + if(xPropSetInfo->hasPropertyByName(PROPERTY_ISNULLABLE)) + SetIsNullable(::comphelper::getINT32(xAffectedCol->getPropertyValue(PROPERTY_ISNULLABLE))); + if(xPropSetInfo->hasPropertyByName(PROPERTY_FORMATKEY)) + { + const Any aValue = xAffectedCol->getPropertyValue(PROPERTY_FORMATKEY); + if ( aValue.hasValue() ) + SetFormatKey(::comphelper::getINT32(aValue)); + } + if(xPropSetInfo->hasPropertyByName(PROPERTY_RELATIVEPOSITION)) + m_aRelativePosition = xAffectedCol->getPropertyValue(PROPERTY_RELATIVEPOSITION); + if(xPropSetInfo->hasPropertyByName(PROPERTY_WIDTH)) + m_aWidth = xAffectedCol->getPropertyValue(PROPERTY_WIDTH); + if(xPropSetInfo->hasPropertyByName(PROPERTY_HIDDEN)) + xAffectedCol->getPropertyValue(PROPERTY_HIDDEN) >>= m_bHidden; + if(xPropSetInfo->hasPropertyByName(PROPERTY_ALIGN)) + { + const Any aValue = xAffectedCol->getPropertyValue(PROPERTY_ALIGN); + if ( aValue.hasValue() ) + SetHorJustify( ::dbaui::mapTextJustify(::comphelper::getINT32(aValue))); + } + if(xPropSetInfo->hasPropertyByName(PROPERTY_ISAUTOINCREMENT)) + SetAutoIncrement(::cppu::any2bool(xAffectedCol->getPropertyValue(PROPERTY_ISAUTOINCREMENT))); + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } +} + +void OFieldDescription::FillFromTypeInfo(const TOTypeInfoSP& _pType,bool _bForce,bool _bReset) +{ + TOTypeInfoSP pOldType = getTypeInfo(); + if ( _pType == pOldType ) + return; + + // reset type depending information + if ( _bReset ) + { + SetFormatKey(0); + SetControlDefault(Any()); + } + + bool bForce = _bForce || !pOldType || pOldType->nType != _pType->nType; + switch ( _pType->nType ) + { + case DataType::CHAR: + case DataType::VARCHAR: + if ( bForce ) + { + sal_Int32 nPrec = DEFAULT_VARCHAR_PRECISION; + if ( GetPrecision() ) + nPrec = GetPrecision(); + SetPrecision(std::min<sal_Int32>(nPrec,_pType->nPrecision)); + } + break; + case DataType::TIMESTAMP: + if ( bForce && _pType->nMaximumScale) + { + SetScale(std::min<sal_Int32>(GetScale() ? GetScale() : DEFAULT_NUMERIC_SCALE,_pType->nMaximumScale)); + } + break; + default: + if ( bForce ) + { + sal_Int32 nPrec = DEFAULT_OTHER_PRECISION; + switch ( _pType->nType ) + { + case DataType::BIT: + case DataType::BLOB: + case DataType::CLOB: + nPrec = _pType->nPrecision; + break; + default: + if ( GetPrecision() ) + nPrec = GetPrecision(); + break; + } + + if ( _pType->nPrecision ) + SetPrecision(std::min<sal_Int32>(nPrec ? nPrec : DEFAULT_NUMERIC_PRECISION,_pType->nPrecision)); + if ( _pType->nMaximumScale ) + SetScale(std::min<sal_Int32>(GetScale() ? GetScale() : DEFAULT_NUMERIC_SCALE,_pType->nMaximumScale)); + } + } + if ( _pType->aCreateParams.isEmpty() ) + { + SetPrecision(_pType->nPrecision); + SetScale(_pType->nMinimumScale); + } + if ( !_pType->bNullable && IsNullable() ) + SetIsNullable(ColumnValue::NO_NULLS); + if ( !_pType->bAutoIncrement && IsAutoIncrement() ) + SetAutoIncrement(false); + SetCurrency( _pType->bCurrency ); + SetType(_pType); + SetTypeName(_pType->aTypeName); +} + +void OFieldDescription::SetName(const OUString& _rName) +{ + try + { + if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_NAME) ) + m_xDest->setPropertyValue(PROPERTY_NAME,Any(_rName)); + else + m_sName = _rName; + } + catch(const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +void OFieldDescription::SetHelpText(const OUString& _sHelpText) +{ + try + { + if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_HELPTEXT) ) + m_xDest->setPropertyValue(PROPERTY_HELPTEXT,Any(_sHelpText)); + else + m_sHelpText = _sHelpText; + } + catch(const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +void OFieldDescription::SetDescription(const OUString& _rDescription) +{ + try + { + if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_DESCRIPTION) ) + m_xDest->setPropertyValue(PROPERTY_DESCRIPTION,Any(_rDescription)); + else + m_sDescription = _rDescription; + } + catch(const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +void OFieldDescription::SetDefaultValue(const Any& _rDefaultValue) +{ + try + { + if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_DEFAULTVALUE) ) + m_xDest->setPropertyValue(PROPERTY_DEFAULTVALUE, _rDefaultValue); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +void OFieldDescription::SetControlDefault(const Any& _rControlDefault) +{ + try + { + if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_CONTROLDEFAULT) ) + m_xDest->setPropertyValue(PROPERTY_CONTROLDEFAULT, _rControlDefault); + else + m_aControlDefault = _rControlDefault; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +void OFieldDescription::SetAutoIncrementValue(const OUString& _sAutoIncValue) +{ + try + { + if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_AUTOINCREMENTCREATION) ) + m_xDest->setPropertyValue(PROPERTY_AUTOINCREMENTCREATION,Any(_sAutoIncValue)); + else + m_sAutoIncrementValue = _sAutoIncValue; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +void OFieldDescription::SetType(const TOTypeInfoSP& _pType) +{ + m_pType = _pType; + if ( !m_pType ) + return; + + try + { + if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_TYPE) ) + m_xDest->setPropertyValue(PROPERTY_TYPE,Any(m_pType->nType)); + else + m_nType = m_pType->nType; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +void OFieldDescription::SetTypeValue(sal_Int32 _nType) +{ + try + { + if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_TYPE) ) + m_xDest->setPropertyValue(PROPERTY_TYPE,Any(_nType)); + else + { + m_nType = _nType; + OSL_ENSURE(!m_pType,"Invalid call here!"); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +void OFieldDescription::SetPrecision(sal_Int32 _rPrecision) +{ + try + { + if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_PRECISION) ) + m_xDest->setPropertyValue(PROPERTY_PRECISION,Any(_rPrecision)); + else + m_nPrecision = _rPrecision; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +void OFieldDescription::SetScale(sal_Int32 _rScale) +{ + try + { + if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_SCALE) ) + m_xDest->setPropertyValue(PROPERTY_SCALE,Any(_rScale)); + else + m_nScale = _rScale; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +void OFieldDescription::SetIsNullable(sal_Int32 _rIsNullable) +{ + try + { + if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_ISNULLABLE) ) + m_xDest->setPropertyValue(PROPERTY_ISNULLABLE,Any(_rIsNullable)); + else + m_nIsNullable = _rIsNullable; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +void OFieldDescription::SetFormatKey(sal_Int32 _rFormatKey) +{ + try + { + if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_FORMATKEY) ) + m_xDest->setPropertyValue(PROPERTY_FORMATKEY,Any(_rFormatKey)); + else + m_nFormatKey = _rFormatKey; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +void OFieldDescription::SetHorJustify(const SvxCellHorJustify& _rHorJustify) +{ + try + { + if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_ALIGN) ) + m_xDest->setPropertyValue(PROPERTY_ALIGN,Any( dbaui::mapTextAlign(_rHorJustify))); + else + m_eHorJustify = _rHorJustify; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +void OFieldDescription::SetAutoIncrement(bool _bAuto) +{ + try + { + if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_ISAUTOINCREMENT) ) + m_xDest->setPropertyValue(PROPERTY_ISAUTOINCREMENT,Any(_bAuto)); + else + m_bIsAutoIncrement = _bAuto; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +void OFieldDescription::SetPrimaryKey(bool _bPKey) +{ + m_bIsPrimaryKey = _bPKey; + if ( _bPKey ) + SetIsNullable(css::sdbc::ColumnValue::NO_NULLS); +} + +void OFieldDescription::SetCurrency(bool _bIsCurrency) +{ + m_bIsCurrency = _bIsCurrency; +} + +OUString OFieldDescription::GetName() const +{ + if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_NAME) ) + return ::comphelper::getString(m_xDest->getPropertyValue(PROPERTY_NAME)); + else + return m_sName; +} + +OUString OFieldDescription::GetDescription() const +{ + if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_DESCRIPTION) ) + return ::comphelper::getString(m_xDest->getPropertyValue(PROPERTY_DESCRIPTION)); + else + return m_sDescription; +} + +OUString OFieldDescription::GetHelpText() const +{ + if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_HELPTEXT) ) + return ::comphelper::getString(m_xDest->getPropertyValue(PROPERTY_HELPTEXT)); + else + return m_sHelpText; +} + +css::uno::Any OFieldDescription::GetControlDefault() const +{ + if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_CONTROLDEFAULT) ) + return m_xDest->getPropertyValue(PROPERTY_CONTROLDEFAULT); + else + return m_aControlDefault; +} + +OUString OFieldDescription::GetAutoIncrementValue() const +{ + if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_AUTOINCREMENTCREATION) ) + return ::comphelper::getString(m_xDest->getPropertyValue(PROPERTY_AUTOINCREMENTCREATION)); + else + return m_sAutoIncrementValue; +} + +sal_Int32 OFieldDescription::GetType() const +{ + if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_TYPE) ) + return ::comphelper::getINT32(m_xDest->getPropertyValue(PROPERTY_TYPE)); + else + return m_pType ? m_pType->nType : m_nType; +} + +OUString OFieldDescription::GetTypeName() const +{ + if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_TYPENAME) ) + return ::comphelper::getString(m_xDest->getPropertyValue(PROPERTY_TYPENAME)); + else + return m_pType ? m_pType->aTypeName : m_sTypeName; +} + +sal_Int32 OFieldDescription::GetPrecision() const +{ + sal_Int32 nPrec = m_nPrecision; + if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_PRECISION) ) + nPrec = ::comphelper::getINT32(m_xDest->getPropertyValue(PROPERTY_PRECISION)); + + TOTypeInfoSP pTypeInfo = getTypeInfo(); + if ( pTypeInfo ) + { + switch ( pTypeInfo->nType ) + { + case DataType::TINYINT: + case DataType::SMALLINT: + case DataType::INTEGER: + case DataType::BIGINT: + if ( !nPrec ) + nPrec = pTypeInfo->nPrecision; + break; + } + } + + return nPrec; +} + +sal_Int32 OFieldDescription::GetScale() const +{ + if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_SCALE) ) + return ::comphelper::getINT32(m_xDest->getPropertyValue(PROPERTY_SCALE)); + else + return m_nScale; +} + +sal_Int32 OFieldDescription::GetIsNullable() const +{ + if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_ISNULLABLE) ) + return ::comphelper::getINT32(m_xDest->getPropertyValue(PROPERTY_ISNULLABLE)); + else + return m_nIsNullable; +} + +sal_Int32 OFieldDescription::GetFormatKey() const +{ + if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_FORMATKEY) ) + return ::comphelper::getINT32(m_xDest->getPropertyValue(PROPERTY_FORMATKEY)); + else + return m_nFormatKey; +} + +SvxCellHorJustify OFieldDescription::GetHorJustify() const +{ + if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_ALIGN) ) + return ::dbaui::mapTextJustify(::comphelper::getINT32(m_xDest->getPropertyValue(PROPERTY_ALIGN))); + else + return m_eHorJustify; +} + + +TOTypeInfoSP OFieldDescription::getSpecialTypeInfo() const +{ + TOTypeInfoSP pSpecialType = std::make_shared<OTypeInfo>(); + *pSpecialType = *m_pType; + pSpecialType->nPrecision = GetPrecision(); + pSpecialType->nMaximumScale = static_cast<sal_Int16>(GetScale()); + pSpecialType->bAutoIncrement = IsAutoIncrement(); // http://dba.openoffice.org/issues/show_bug.cgi?id=115398 fixed by ludob + return pSpecialType; +} + +bool OFieldDescription::IsAutoIncrement() const +{ + if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_ISAUTOINCREMENT) ) + return ::cppu::any2bool(m_xDest->getPropertyValue(PROPERTY_ISAUTOINCREMENT)); + else + return m_bIsAutoIncrement; +} + + +bool OFieldDescription::IsNullable() const +{ + if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_ISNULLABLE) ) + return ::comphelper::getINT32(m_xDest->getPropertyValue(PROPERTY_ISNULLABLE)) == css::sdbc::ColumnValue::NULLABLE; + else + return m_nIsNullable == css::sdbc::ColumnValue::NULLABLE; +} + +void OFieldDescription::SetTypeName(const OUString& _sTypeName) +{ + try + { + if ( m_xDest.is() && m_xDestInfo->hasPropertyByName(PROPERTY_TYPENAME) ) + m_xDest->setPropertyValue(PROPERTY_TYPENAME,Any(_sTypeName)); + else + m_sTypeName = _sTypeName; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +void OFieldDescription::copyColumnSettingsTo(const Reference< XPropertySet >& _rxColumn) +{ + if ( !_rxColumn.is() ) + return; + + Reference<XPropertySetInfo> xInfo = _rxColumn->getPropertySetInfo(); + + if ( GetFormatKey() != NumberFormat::ALL && xInfo->hasPropertyByName(PROPERTY_FORMATKEY) ) + _rxColumn->setPropertyValue(PROPERTY_FORMATKEY,Any(GetFormatKey())); + if ( GetHorJustify() != SvxCellHorJustify::Standard && xInfo->hasPropertyByName(PROPERTY_ALIGN) ) + _rxColumn->setPropertyValue(PROPERTY_ALIGN,Any(dbaui::mapTextAlign(GetHorJustify()))); + if ( !GetHelpText().isEmpty() && xInfo->hasPropertyByName(PROPERTY_HELPTEXT) ) + _rxColumn->setPropertyValue(PROPERTY_HELPTEXT,Any(GetHelpText())); + if ( GetControlDefault().hasValue() && xInfo->hasPropertyByName(PROPERTY_CONTROLDEFAULT) ) + _rxColumn->setPropertyValue(PROPERTY_CONTROLDEFAULT,GetControlDefault()); + + if(xInfo->hasPropertyByName(PROPERTY_RELATIVEPOSITION)) + _rxColumn->setPropertyValue(PROPERTY_RELATIVEPOSITION,m_aRelativePosition); + if(xInfo->hasPropertyByName(PROPERTY_WIDTH)) + _rxColumn->setPropertyValue(PROPERTY_WIDTH,m_aWidth); + if(xInfo->hasPropertyByName(PROPERTY_HIDDEN)) + _rxColumn->setPropertyValue(PROPERTY_HIDDEN,Any(m_bHidden)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/tabledesign/TEditControl.cxx b/dbaccess/source/ui/tabledesign/TEditControl.cxx new file mode 100644 index 000000000..5f7809882 --- /dev/null +++ b/dbaccess/source/ui/tabledesign/TEditControl.cxx @@ -0,0 +1,1679 @@ +/* -*- 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 "TEditControl.hxx" +#include <com/sun/star/sdbc/ColumnValue.hpp> +#include <com/sun/star/sdbc/SQLException.hpp> +#include <com/sun/star/sdbc/XDatabaseMetaData.hpp> +#include <com/sun/star/sdbcx/XColumnsSupplier.hpp> +#include <com/sun/star/util/XNumberFormatTypes.hpp> +#include <core_resource.hxx> +#include <strings.hrc> +#include <strings.hxx> +#include <helpids.h> +#include <comphelper/types.hxx> +#include <FieldDescControl.hxx> +#include <FieldDescriptions.hxx> +#include "TableUndo.hxx" +#include <TableController.hxx> +#include <connectivity/dbmetadata.hxx> +#include <connectivity/dbtools.hxx> +#include <SqlNameEdit.hxx> +#include <TableRowExchange.hxx> +#include <o3tl/safeint.hxx> +#include <sot/storage.hxx> +#include <svx/svxids.hrc> +#include <UITools.hxx> +#include "TableFieldControl.hxx" +#include <dsntypes.hxx> +#include <vcl/commandevent.hxx> +#include <vcl/svapp.hxx> + +using namespace ::dbaui; +using namespace ::comphelper; +using namespace ::svt; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::io; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::sdb; + + +#define HANDLE_ID 0 + +// default field widths +#define FIELDNAME_WIDTH 100 +#define FIELDTYPE_WIDTH 150 +#define FIELDDESCR_WIDTH 300 + +// Maximum length in description field +#define MAX_DESCR_LEN 256 + +OTableEditorCtrl::ClipboardInvalidator::ClipboardInvalidator(OTableEditorCtrl* _pOwner) +: m_aInvalidateTimer("dbaccess ClipboardInvalidator") +, m_pOwner(_pOwner) +{ + + m_aInvalidateTimer.SetTimeout(500); + m_aInvalidateTimer.SetInvokeHandler(LINK(this, OTableEditorCtrl::ClipboardInvalidator, OnInvalidate)); + m_aInvalidateTimer.Start(); +} + +OTableEditorCtrl::ClipboardInvalidator::~ClipboardInvalidator() +{ + m_aInvalidateTimer.Stop(); +} + +void OTableEditorCtrl::ClipboardInvalidator::Stop() +{ + m_aInvalidateTimer.Stop(); +} + +IMPL_LINK_NOARG(OTableEditorCtrl::ClipboardInvalidator, OnInvalidate, Timer *, void) +{ + m_pOwner->GetView()->getController().InvalidateFeature(SID_CUT); + m_pOwner->GetView()->getController().InvalidateFeature(SID_COPY); + m_pOwner->GetView()->getController().InvalidateFeature(SID_PASTE); +} + +void OTableEditorCtrl::Init() +{ + OTableRowView::Init(); + + // Should it be opened ReadOnly? + bool bRead(GetView()->getController().isReadOnly()); + + SetReadOnly( bRead ); + + // Insert the columns + InsertDataColumn( FIELD_NAME, DBA_RES(STR_TAB_FIELD_COLUMN_NAME), FIELDNAME_WIDTH ); + + InsertDataColumn( FIELD_TYPE, DBA_RES(STR_TAB_FIELD_COLUMN_DATATYPE), FIELDTYPE_WIDTH ); + + ::dbaccess::ODsnTypeCollection aDsnTypes(GetView()->getController().getORB()); + bool bShowColumnDescription = aDsnTypes.supportsColumnDescription(::comphelper::getString(GetView()->getController().getDataSource()->getPropertyValue(PROPERTY_URL))); + InsertDataColumn( HELP_TEXT, DBA_RES(STR_TAB_HELP_TEXT), bShowColumnDescription ? FIELDTYPE_WIDTH : FIELDDESCR_WIDTH ); + + if ( bShowColumnDescription ) + { + InsertDataColumn( COLUMN_DESCRIPTION, DBA_RES(STR_COLUMN_DESCRIPTION), FIELDTYPE_WIDTH ); + } + + InitCellController(); + + // Insert the rows + RowInserted(0, m_pRowList->size()); +} + +OTableEditorCtrl::OTableEditorCtrl(vcl::Window* pWindow, OTableDesignView* pView) + :OTableRowView(pWindow) + ,m_pView(pView) + ,pNameCell(nullptr) + ,pTypeCell(nullptr) + ,pHelpTextCell(nullptr) + ,pDescrCell(nullptr) + ,pDescrWin(nullptr) + ,nCutEvent(nullptr) + ,nPasteEvent(nullptr) + ,nDeleteEvent(nullptr) + ,nInsNewRowsEvent(nullptr) + ,nInvalidateTypeEvent(nullptr) + ,m_eChildFocus(NONE) + ,nOldDataPos(-1) + ,bReadOnly(true) + ,m_aInvalidate(this) +{ + SetHelpId(HID_TABDESIGN_BACKGROUND); + GetDataWindow().SetHelpId(HID_CTL_TABLEEDIT); + + m_pRowList = &GetView()->getController().getRows(); + m_nDataPos = 0; +} + +SfxUndoManager& OTableEditorCtrl::GetUndoManager() const +{ + return GetView()->getController().GetUndoManager(); +} + + +void OTableEditorCtrl::SetReadOnly( bool bRead ) +{ + // nothing to do? + if (bRead == IsReadOnly()) + // This check is important, as the underlying Def may be unnecessarily locked or unlocked + // or worse, this action may not be reversed afterwards + return; + + bReadOnly = bRead; + + // Disable active cells + sal_Int32 nRow(GetCurRow()); + sal_uInt16 nCol(GetCurColumnId()); + DeactivateCell(); + + // Select the correct Browsers cursor + BrowserMode nMode(BrowserMode::COLUMNSELECTION | BrowserMode::MULTISELECTION | BrowserMode::KEEPHIGHLIGHT | + BrowserMode::HLINES | BrowserMode::VLINES|BrowserMode::AUTOSIZE_LASTCOL); + if( !bReadOnly ) + nMode |= BrowserMode::HIDECURSOR; + SetMode(nMode); + + if( !bReadOnly ) + ActivateCell( nRow, nCol ); +} + +void OTableEditorCtrl::InitCellController() +{ + // Cell Field name + sal_Int32 nMaxTextLen = 0; + OUString sExtraNameChars; + Reference<XConnection> xCon; + try + { + xCon = GetView()->getController().getConnection(); + Reference< XDatabaseMetaData> xMetaData = xCon.is() ? xCon->getMetaData() : Reference< XDatabaseMetaData>(); + + // length 0 is treated by Entry::set_max_length as unlimited + nMaxTextLen = xMetaData.is() ? xMetaData->getMaxColumnNameLength() : 0; + + sExtraNameChars = xMetaData.is() ? xMetaData->getExtraNameCharacters() : OUString(); + + } + catch(SQLException&) + { + OSL_FAIL("getMaxColumnNameLength"); + } + + pNameCell = VclPtr<OSQLNameEditControl>::Create(&GetDataWindow(), sExtraNameChars); + pNameCell->get_widget().set_max_length(nMaxTextLen); + pNameCell->setCheck( isSQL92CheckEnabled(xCon) ); + + // Cell type + pTypeCell = VclPtr<ListBoxControl>::Create( &GetDataWindow() ); + + // Cell description + pDescrCell = VclPtr<EditControl>::Create(&GetDataWindow()); + pDescrCell->get_widget().set_max_length(MAX_DESCR_LEN); + + pHelpTextCell = VclPtr<EditControl>::Create(&GetDataWindow()); + pHelpTextCell->get_widget().set_max_length(MAX_DESCR_LEN); + + pNameCell->SetHelpId(HID_TABDESIGN_NAMECELL); + pTypeCell->SetHelpId(HID_TABDESIGN_TYPECELL); + pDescrCell->SetHelpId(HID_TABDESIGN_COMMENTCELL); + pHelpTextCell->SetHelpId(HID_TABDESIGN_HELPTEXT); + + Size aHeight; + const Control* pControls[] = { pTypeCell,pDescrCell,pNameCell,pHelpTextCell}; + for(const Control* pControl : pControls) + { + const Size aTemp(pControl->GetOptimalSize()); + if ( aTemp.Height() > aHeight.Height() ) + aHeight.setHeight( aTemp.Height() ); + } + SetDataRowHeight(aHeight.Height()); + + ClearModified(); +} + +void OTableEditorCtrl::ClearModified() +{ + pNameCell->get_widget().save_value(); + pDescrCell->get_widget().save_value(); + pHelpTextCell->get_widget().save_value(); + pTypeCell->get_widget().save_value(); +} + +OTableEditorCtrl::~OTableEditorCtrl() +{ + disposeOnce(); +} + +void OTableEditorCtrl::dispose() +{ + // Reset the Undo-Manager + GetUndoManager().Clear(); + + m_aInvalidate.Stop(); + + // Take possible Events from the queue + if( nCutEvent ) + Application::RemoveUserEvent( nCutEvent ); + if( nPasteEvent ) + Application::RemoveUserEvent( nPasteEvent ); + if( nDeleteEvent ) + Application::RemoveUserEvent( nDeleteEvent ); + if( nInsNewRowsEvent ) + Application::RemoveUserEvent( nInsNewRowsEvent ); + if( nInvalidateTypeEvent ) + Application::RemoveUserEvent( nInvalidateTypeEvent ); + + // Delete the control types + pNameCell.disposeAndClear(); + pTypeCell.disposeAndClear(); + pDescrCell.disposeAndClear(); + pHelpTextCell.disposeAndClear(); + pDescrWin = nullptr; + m_pView.clear(); + OTableRowView::dispose(); +} + +bool OTableEditorCtrl::SetDataPtr( sal_Int32 nRow ) +{ + if(nRow == -1) + return false; + + OSL_ENSURE(nRow < static_cast<tools::Long>(m_pRowList->size()),"Row is greater than size!"); + if(nRow >= static_cast<tools::Long>(m_pRowList->size())) + return false; + pActRow = (*m_pRowList)[nRow]; + return pActRow != nullptr; +} + +bool OTableEditorCtrl::SeekRow(sal_Int32 _nRow) +{ + // Call the Base class to remember which row must be repainted + EditBrowseBox::SeekRow(_nRow); + + m_nCurrentPos = _nRow; + return SetDataPtr(_nRow); +} + +void OTableEditorCtrl::PaintCell(OutputDevice& rDev, const tools::Rectangle& rRect, + sal_uInt16 nColumnId ) const +{ + const OUString aText( GetCellText( m_nCurrentPos, nColumnId )); + + rDev.Push( vcl::PushFlags::CLIPREGION ); + rDev.SetClipRegion(vcl::Region(rRect)); + rDev.DrawText( rRect, aText, DrawTextFlags::Left | DrawTextFlags::VCenter ); + rDev.Pop(); +} + +CellController* OTableEditorCtrl::GetController(sal_Int32 nRow, sal_uInt16 nColumnId) +{ + // If EditorCtrl is ReadOnly, editing is forbidden + Reference<XPropertySet> xTable = GetView()->getController().getTable(); + if (IsReadOnly() || ( xTable.is() && + xTable->getPropertySetInfo()->hasPropertyByName(PROPERTY_TYPE) && + ::comphelper::getString(xTable->getPropertyValue(PROPERTY_TYPE)) == "VIEW")) + return nullptr; + + // If the row is ReadOnly, editing is forbidden + SetDataPtr( nRow ); + if( pActRow->IsReadOnly() ) + return nullptr; + + OFieldDescription* pActFieldDescr = pActRow->GetActFieldDescr(); + switch (nColumnId) + { + case FIELD_NAME: + return new EditCellController( pNameCell ); + case FIELD_TYPE: + if (pActFieldDescr && !pActFieldDescr->GetName().isEmpty()) + return new ListBoxCellController( pTypeCell ); + else return nullptr; + case HELP_TEXT: + if (pActFieldDescr && !pActFieldDescr->GetName().isEmpty()) + return new EditCellController( pHelpTextCell ); + else + return nullptr; + case COLUMN_DESCRIPTION: + if (pActFieldDescr && !pActFieldDescr->GetName().isEmpty()) + return new EditCellController( pDescrCell ); + else + return nullptr; + default: + return nullptr; + } +} + +void OTableEditorCtrl::InitController(CellControllerRef&, sal_Int32 nRow, sal_uInt16 nColumnId) +{ + SeekRow( nRow == -1 ? GetCurRow() : nRow); + OFieldDescription* pActFieldDescr = pActRow->GetActFieldDescr(); + OUString aInitString; + + switch (nColumnId) + { + case FIELD_NAME: + { + if( pActFieldDescr ) + aInitString = pActFieldDescr->GetName(); + + weld::Entry& rEntry = pNameCell->get_widget(); + rEntry.set_text(aInitString); + rEntry.save_value(); + break; + } + case FIELD_TYPE: + { + if ( pActFieldDescr && pActFieldDescr->getTypeInfo() ) + aInitString = pActFieldDescr->getTypeInfo()->aUIName; + + // Set the ComboBox contents + weld::ComboBox& rTypeList = pTypeCell->get_widget(); + rTypeList.clear(); + if( !pActFieldDescr ) + break; + + const OTypeInfoMap& rTypeInfo = GetView()->getController().getTypeInfo(); + for (auto const& elem : rTypeInfo) + rTypeList.append_text(elem.second->aUIName); + rTypeList.set_active_text(aInitString); + } + + break; + case HELP_TEXT: + { + if( pActFieldDescr ) + aInitString = pActFieldDescr->GetHelpText(); + weld::Entry& rEntry = pHelpTextCell->get_widget(); + rEntry.set_text(aInitString); + rEntry.save_value(); + break; + } + case COLUMN_DESCRIPTION: + { + if( pActFieldDescr ) + aInitString = pActFieldDescr->GetDescription(); + weld::Entry& rEntry = pDescrCell->get_widget(); + rEntry.set_text(aInitString); + rEntry.save_value(); + break; + } + } +} + +EditBrowseBox::RowStatus OTableEditorCtrl::GetRowStatus(sal_Int32 nRow) const +{ + const_cast<OTableEditorCtrl*>(this)->SetDataPtr( nRow ); + if( !pActRow ) + return EditBrowseBox::CLEAN; + if (nRow >= 0 && nRow == m_nDataPos) + { + if( pActRow->IsPrimaryKey() ) + return EditBrowseBox::CURRENT_PRIMARYKEY; + return EditBrowseBox::CURRENT; + } + else + { + if( pActRow->IsPrimaryKey() ) + return EditBrowseBox::PRIMARYKEY; + return EditBrowseBox::CLEAN; + } +} + +void OTableEditorCtrl::SaveCurRow() +{ + if (GetFieldDescr(GetCurRow()) == nullptr) + // there is no data in the current row + return; + if (!SaveModified()) + return; + + SetDataPtr(GetCurRow()); + pDescrWin->SaveData( pActRow->GetActFieldDescr() ); +} + +void OTableEditorCtrl::DisplayData(sal_Int32 nRow) +{ + // go to the correct cell + SetDataPtr(nRow); + + // Disable Edit-Mode temporarily + bool bWasEditing = IsEditing(); + if (bWasEditing) + DeactivateCell(); + + CellControllerRef aTemp; + InitController(aTemp, nRow, FIELD_NAME); + InitController(aTemp, nRow, FIELD_TYPE); + InitController(aTemp, nRow, COLUMN_DESCRIPTION); + InitController(aTemp, nRow, HELP_TEXT); + + GoToRow(nRow); + // Update the Description-Window + GetView()->GetDescWin()->DisplayData(GetFieldDescr(nRow)); + // redraw the row + RowModified(nRow); + + // and re-enable edit mode + ActivateCell(nRow, GetCurColumnId()); +} + +void OTableEditorCtrl::CursorMoved() +{ + // New line? + m_nDataPos = GetCurRow(); + if( m_nDataPos != nOldDataPos && m_nDataPos != -1) + { + CellControllerRef aTemp; + InitController(aTemp,m_nDataPos,FIELD_NAME); + InitController(aTemp,m_nDataPos,FIELD_TYPE); + InitController(aTemp,m_nDataPos,COLUMN_DESCRIPTION); + InitController(aTemp,m_nDataPos,HELP_TEXT); + } + + OTableRowView::CursorMoved(); +} + +sal_Int32 OTableEditorCtrl::HasFieldName( std::u16string_view rFieldName ) +{ + + Reference<XConnection> xCon = GetView()->getController().getConnection(); + Reference< XDatabaseMetaData> xMetaData = xCon.is() ? xCon->getMetaData() : Reference< XDatabaseMetaData>(); + + ::comphelper::UStringMixEqual bCase(!xMetaData.is() || xMetaData->supportsMixedCaseQuotedIdentifiers()); + + sal_Int32 nCount(0); + for (auto const& row : *m_pRowList) + { + OFieldDescription* pFieldDescr = row->GetActFieldDescr(); + if( pFieldDescr && bCase(rFieldName,pFieldDescr->GetName())) + nCount++; + } + return nCount; +} + +void OTableEditorCtrl::SaveData(sal_Int32 nRow, sal_uInt16 nColId) +{ + // Store the cell content + SetDataPtr( nRow == -1 ? GetCurRow() : nRow); + OFieldDescription* pActFieldDescr = pActRow->GetActFieldDescr(); + + switch( nColId) + { + // Store NameCell + case FIELD_NAME: + { + // If there is no name, do nothing + weld::Entry& rEntry = pNameCell->get_widget(); + const OUString aName(rEntry.get_text()); + + if( aName.isEmpty() ) + { + // If FieldDescr exists, the field is deleted and the old content restored + if (pActFieldDescr) + { + GetUndoManager().AddUndoAction(std::make_unique<OTableEditorTypeSelUndoAct>(this, nRow, FIELD_TYPE, pActFieldDescr->getTypeInfo())); + SwitchType(TOTypeInfoSP()); + pActFieldDescr = pActRow->GetActFieldDescr(); + } + else + return; + } + if(pActFieldDescr) + pActFieldDescr->SetName( aName ); + rEntry.save_value(); + + break; + } + + // Store the field type + case FIELD_TYPE: + break; + + // Store DescrCell + case HELP_TEXT: + { + // if the current field description is NULL, set Default + weld::Entry& rEntry = pHelpTextCell->get_widget(); + if( !pActFieldDescr ) + { + rEntry.set_text(OUString()); + rEntry.save_value(); + } + else + pActFieldDescr->SetHelpText(rEntry.get_text()); + break; + } + case COLUMN_DESCRIPTION: + { + // Set the default if the field description is null + weld::Entry& rEntry = pDescrCell->get_widget(); + if( !pActFieldDescr ) + { + rEntry.set_text(OUString()); + rEntry.save_value(); + } + else + pActFieldDescr->SetDescription(rEntry.get_text()); + break; + } + case FIELD_PROPERTY_DEFAULT: + case FIELD_PROPERTY_REQUIRED: + case FIELD_PROPERTY_TEXTLEN: + case FIELD_PROPERTY_NUMTYPE: + case FIELD_PROPERTY_AUTOINC: + case FIELD_PROPERTY_LENGTH: + case FIELD_PROPERTY_SCALE: + case FIELD_PROPERTY_BOOL_DEFAULT: + pDescrWin->SaveData(pActFieldDescr); + + if ( FIELD_PROPERTY_AUTOINC == nColId && pActFieldDescr->IsAutoIncrement() ) + { + OTableController& rController = GetView()->getController(); + if ( rController.isAutoIncrementPrimaryKey() ) + { + pActFieldDescr->SetPrimaryKey( true ); + InvalidateHandleColumn(); + Invalidate(); + } + } + break; + } +} + +bool OTableEditorCtrl::SaveModified() +{ + sal_uInt16 nColId = GetCurColumnId(); + + switch( nColId ) + { + // Field type + case FIELD_TYPE: + { + // Reset the type + resetType(); + } break; + } + + return true; +} + +bool OTableEditorCtrl::CursorMoving(sal_Int32 nNewRow, sal_uInt16 nNewCol) +{ + + if (!EditBrowseBox::CursorMoving(nNewRow, nNewCol)) + return false; + + // Called after SaveModified(), current row is still the old one + m_nDataPos = nNewRow; + nOldDataPos = GetCurRow(); + + // Reset the markers + InvalidateStatusCell( nOldDataPos ); + InvalidateStatusCell( m_nDataPos ); + + // Store the data from the Property window + if( SetDataPtr(nOldDataPos) && pDescrWin) + pDescrWin->SaveData( pActRow->GetActFieldDescr() ); + + // Show new data in the Property window + if( SetDataPtr(m_nDataPos) && pDescrWin) + pDescrWin->DisplayData( pActRow->GetActFieldDescr() ); + + return true; +} + +IMPL_LINK_NOARG( OTableEditorCtrl, InvalidateFieldType, void*, void ) +{ + nInvalidateTypeEvent = nullptr; + Invalidate( GetFieldRectPixel(nOldDataPos, FIELD_TYPE) ); +} + +void OTableEditorCtrl::CellModified( sal_Int32 nRow, sal_uInt16 nColId ) +{ + + // If the description is null, use the default + if(nRow == -1) + nRow = GetCurRow(); + SetDataPtr( nRow ); + OFieldDescription* pActFieldDescr = pActRow->GetActFieldDescr(); + + OUString sActionDescription; + switch ( nColId ) + { + case FIELD_NAME: sActionDescription = DBA_RES( STR_CHANGE_COLUMN_NAME ); break; + case FIELD_TYPE: sActionDescription = DBA_RES( STR_CHANGE_COLUMN_TYPE ); break; + case HELP_TEXT: + case COLUMN_DESCRIPTION: sActionDescription = DBA_RES( STR_CHANGE_COLUMN_DESCRIPTION ); break; + default: sActionDescription = DBA_RES( STR_CHANGE_COLUMN_ATTRIBUTE ); break; + } + + GetUndoManager().EnterListAction( sActionDescription, OUString(), 0, ViewShellId(-1) ); + if (!pActFieldDescr) + { + const OTypeInfoMap& rTypeInfoMap = GetView()->getController().getTypeInfo(); + if ( !rTypeInfoMap.empty() ) + { + OTypeInfoMap::const_iterator aTypeIter = rTypeInfoMap.find(DataType::VARCHAR); + if ( aTypeIter == rTypeInfoMap.end() ) + aTypeIter = rTypeInfoMap.begin(); + pActRow->SetFieldType( aTypeIter->second ); + } + else + pActRow->SetFieldType( GetView()->getController().getTypeInfoFallBack() ); + + nInvalidateTypeEvent = Application::PostUserEvent( LINK(this, OTableEditorCtrl, InvalidateFieldType), nullptr, true ); + pActFieldDescr = pActRow->GetActFieldDescr(); + pDescrWin->DisplayData( pActFieldDescr ); + GetUndoManager().AddUndoAction( std::make_unique<OTableEditorTypeSelUndoAct>(this, nRow, nColId+1, TOTypeInfoSP()) ); + } + + if( nColId != FIELD_TYPE ) + GetUndoManager().AddUndoAction( std::make_unique<OTableDesignCellUndoAct>(this, nRow, nColId) ); + else + { + GetUndoManager().AddUndoAction(std::make_unique<OTableEditorTypeSelUndoAct>(this, GetCurRow(), nColId, GetFieldDescr(GetCurRow())->getTypeInfo())); + resetType(); + } + + SaveData(nRow,nColId); + // SaveData could create an undo action as well + GetUndoManager().LeaveListAction(); + RowModified(nRow); + + // Set the Modify flag + GetView()->getController().setModified( true ); + InvalidateFeatures(); +} + +void OTableEditorCtrl::resetType() +{ + sal_Int32 nPos = pTypeCell->get_widget().get_active(); + if(nPos != -1) + SwitchType( GetView()->getController().getTypeInfo(nPos) ); + else + SwitchType(TOTypeInfoSP()); +} + +void OTableEditorCtrl::CellModified() +{ + CellModified( GetCurRow(), GetCurColumnId() ); +} + +void OTableEditorCtrl::InvalidateFeatures() +{ + GetView()->getController().InvalidateFeature(SID_UNDO); + GetView()->getController().InvalidateFeature(SID_REDO); + GetView()->getController().InvalidateFeature(SID_SAVEDOC); +} + +void OTableEditorCtrl::CopyRows() +{ + // set to the right row and save it + if( SetDataPtr(m_nDataPos) ) + pDescrWin->SaveData( pActRow->GetActFieldDescr() ); + + // Copy selected rows to the ClipboardList + std::shared_ptr<OTableRow> pClipboardRow; + std::shared_ptr<OTableRow> pRow; + std::vector< std::shared_ptr<OTableRow> > vClipboardList; + vClipboardList.reserve(GetSelectRowCount()); + + for( tools::Long nIndex=FirstSelectedRow(); nIndex != SFX_ENDOFSELECTION; nIndex=NextSelectedRow() ) + { + pRow = (*m_pRowList)[nIndex]; + OSL_ENSURE(pRow,"OTableEditorCtrl::CopyRows: Row is NULL!"); + if ( pRow && pRow->GetActFieldDescr() ) + { + pClipboardRow = std::make_shared<OTableRow>( *pRow ); + vClipboardList.push_back( pClipboardRow); + } + } + if(!vClipboardList.empty()) + { + rtl::Reference<OTableRowExchange> pData = new OTableRowExchange(std::move(vClipboardList)); + pData->CopyToClipboard(GetParent()); + } +} + +OUString OTableEditorCtrl::GenerateName( const OUString& rName ) +{ + // Create a base name for appending numbers to + OUString aBaseName; + Reference<XConnection> xCon = GetView()->getController().getConnection(); + Reference< XDatabaseMetaData> xMetaData = xCon.is() ? xCon->getMetaData() : Reference< XDatabaseMetaData>(); + + sal_Int32 nMaxTextLen(xMetaData.is() ? xMetaData->getMaxColumnNameLength() : 0); + + if( (rName.getLength()+2) >nMaxTextLen ) + aBaseName = rName.copy( 0, nMaxTextLen-2 ); + else + aBaseName = rName; + + // append a sequential number to the base name (up to 99) + OUString aFieldName( rName); + sal_Int32 i=1; + while( HasFieldName(aFieldName) ) + { + aFieldName = aBaseName + OUString::number(i); + i++; + } + + return aFieldName; +} + +void OTableEditorCtrl::InsertRows( sal_Int32 nRow ) +{ + + std::vector< std::shared_ptr<OTableRow> > vInsertedUndoRedoRows; // need for undo/redo handling + // get rows from clipboard + TransferableDataHelper aTransferData(TransferableDataHelper::CreateFromSystemClipboard(GetParent())); + if(aTransferData.HasFormat(SotClipboardFormatId::SBA_TABED)) + { + ::tools::SvRef<SotTempStream> aStreamRef; + bool bOk = aTransferData.GetSotStorageStream(SotClipboardFormatId::SBA_TABED,aStreamRef); + if (bOk && aStreamRef.is()) + { + aStreamRef->Seek(STREAM_SEEK_TO_BEGIN); + aStreamRef->ResetError(); + sal_Int32 nInsertRow = nRow; + std::shared_ptr<OTableRow> pRow; + sal_Int32 nSize = 0; + (*aStreamRef).ReadInt32( nSize ); + vInsertedUndoRedoRows.reserve(nSize); + for(sal_Int32 i=0;i < nSize;++i) + { + pRow = std::make_shared<OTableRow>(); + ReadOTableRow( *aStreamRef, *pRow ); + pRow->SetReadOnly( false ); + sal_Int32 nType = pRow->GetActFieldDescr()->GetType(); + if ( pRow->GetActFieldDescr() ) + pRow->GetActFieldDescr()->SetType(GetView()->getController().getTypeInfoByType(nType)); + // Adjust the field names + pRow->GetActFieldDescr()->SetName( GenerateName( pRow->GetActFieldDescr()->GetName() ) ); + pRow->SetPos(nInsertRow); + m_pRowList->insert( m_pRowList->begin()+nInsertRow,pRow ); + vInsertedUndoRedoRows.push_back(std::make_shared<OTableRow>(*pRow)); + nInsertRow++; + } + } + } + // RowInserted calls CursorMoved. + // The UI data should not be stored here. + RowInserted( nRow,vInsertedUndoRedoRows.size() ); + + // Create the Undo-Action + GetUndoManager().AddUndoAction( std::make_unique<OTableEditorInsUndoAct>(this, nRow, std::move(vInsertedUndoRedoRows)) ); + GetView()->getController().setModified( true ); + InvalidateFeatures(); +} + +void OTableEditorCtrl::DeleteRows() +{ + OSL_ENSURE(GetView()->getController().isDropAllowed(),"Call of DeleteRows not valid here. Please check isDropAllowed!"); + // Create the Undo-Action + GetUndoManager().AddUndoAction( std::make_unique<OTableEditorDelUndoAct>(this) ); + + // Delete all marked rows + tools::Long nIndex = FirstSelectedRow(); + nOldDataPos = nIndex; + + while( nIndex != SFX_ENDOFSELECTION ) + { + // Remove rows + m_pRowList->erase( m_pRowList->begin()+nIndex ); + RowRemoved( nIndex ); + + // Insert the empty row at the end + m_pRowList->push_back( std::make_shared<OTableRow>()); + RowInserted( GetRowCount()-1 ); + + nIndex = FirstSelectedRow(); + } + + // Force the current record to be displayed + m_nDataPos = GetCurRow(); + InvalidateStatusCell( nOldDataPos ); + InvalidateStatusCell( m_nDataPos ); + SetDataPtr( m_nDataPos ); + ActivateCell(); + pDescrWin->DisplayData( pActRow->GetActFieldDescr() ); + GetView()->getController().setModified( true ); + InvalidateFeatures(); +} + +void OTableEditorCtrl::InsertNewRows( sal_Int32 nRow ) +{ + OSL_ENSURE(GetView()->getController().isAddAllowed(),"Call of InsertNewRows not valid here. Please check isAppendAllowed!"); + // Create Undo-Action + sal_Int32 nInsertRows = GetSelectRowCount(); + if( !nInsertRows ) + nInsertRows = 1; + GetUndoManager().AddUndoAction( std::make_unique<OTableEditorInsNewUndoAct>(this, nRow, nInsertRows) ); + // Insert the number of selected rows + for( tools::Long i=nRow; i<(nRow+nInsertRows); i++ ) + m_pRowList->insert( m_pRowList->begin()+i ,std::make_shared<OTableRow>()); + RowInserted( nRow, nInsertRows ); + + GetView()->getController().setModified( true ); + InvalidateFeatures(); +} + +void OTableEditorCtrl::SetControlText( sal_Int32 nRow, sal_uInt16 nColId, const OUString& rText ) +{ + // Set the Browser Controls + if( nColId < FIELD_FIRST_VIRTUAL_COLUMN ) + { + GoToRow( nRow ); + GoToColumnId( nColId ); + CellControllerRef xController = Controller(); + if(xController.is()) + xController->GetWindow().SetText( rText ); + else + RowModified(nRow,nColId); + } + + // Set the Tabpage controls + else + { + pDescrWin->SetControlText( nColId, rText ); + } +} + +void OTableEditorCtrl::SetCellData( sal_Int32 nRow, sal_uInt16 nColId, const TOTypeInfoSP& _pTypeInfo ) +{ + // Relocate the current pointer + if( nRow == -1 ) + nRow = GetCurRow(); + OFieldDescription* pFieldDescr = GetFieldDescr( nRow ); + if( !pFieldDescr && nColId != FIELD_TYPE) + return; + + // Set individual fields + switch( nColId ) + { + case FIELD_TYPE: + SwitchType( _pTypeInfo ); + break; + default: + OSL_FAIL("OTableEditorCtrl::SetCellData: invalid column!"); + } + SetControlText(nRow,nColId,_pTypeInfo ? _pTypeInfo->aUIName : OUString()); +} + +void OTableEditorCtrl::SetCellData( sal_Int32 nRow, sal_uInt16 nColId, const css::uno::Any& _rNewData ) +{ + // Relocate the current pointer + if( nRow == -1 ) + nRow = GetCurRow(); + OFieldDescription* pFieldDescr = GetFieldDescr( nRow ); + if( !pFieldDescr && nColId != FIELD_TYPE) + return; + + OUString sValue; + // Set individual fields + switch( nColId ) + { + case FIELD_NAME: + sValue = ::comphelper::getString(_rNewData); + pFieldDescr->SetName( sValue ); + break; + + case FIELD_TYPE: + OSL_FAIL("OTableEditorCtrl::SetCellData: invalid column!"); + break; + + case COLUMN_DESCRIPTION: + sValue = ::comphelper::getString(_rNewData); + pFieldDescr->SetDescription( sValue ); + break; + + case FIELD_PROPERTY_DEFAULT: + pFieldDescr->SetControlDefault( _rNewData ); + sValue = GetView()->GetDescWin()->getGenPage()->getControlDefault(pFieldDescr); + break; + + case FIELD_PROPERTY_REQUIRED: + { + sValue = ::comphelper::getString(_rNewData); + pFieldDescr->SetIsNullable( sValue.toInt32() ); + } + break; + + case FIELD_PROPERTY_TEXTLEN: + case FIELD_PROPERTY_LENGTH: + { + sValue = ::comphelper::getString(_rNewData); + pFieldDescr->SetPrecision( sValue.toInt32() ); + } + break; + + case FIELD_PROPERTY_NUMTYPE: + OSL_FAIL("OTableEditorCtrl::SetCellData: invalid column!"); + break; + + case FIELD_PROPERTY_AUTOINC: + { + sValue = ::comphelper::getString(_rNewData); + pFieldDescr->SetAutoIncrement(sValue == DBA_RES(STR_VALUE_YES)); + } + break; + case FIELD_PROPERTY_SCALE: + { + sValue = ::comphelper::getString(_rNewData); + pFieldDescr->SetScale(sValue.toInt32()); + } + break; + + case FIELD_PROPERTY_BOOL_DEFAULT: + sValue = GetView()->GetDescWin()->BoolStringPersistent(::comphelper::getString(_rNewData)); + pFieldDescr->SetControlDefault(Any(sValue)); + break; + + case FIELD_PROPERTY_FORMAT: + { + sValue = ::comphelper::getString(_rNewData); + pFieldDescr->SetFormatKey(sValue.toInt32()); + } + break; + } + + SetControlText(nRow,nColId,sValue); +} + +Any OTableEditorCtrl::GetCellData( sal_Int32 nRow, sal_uInt16 nColId ) +{ + OFieldDescription* pFieldDescr = GetFieldDescr( nRow ); + if( !pFieldDescr ) + return Any(); + + // Relocate the current pointer + if( nRow==-1 ) + nRow = GetCurRow(); + SetDataPtr( nRow ); + + static const OUString strYes(DBA_RES(STR_VALUE_YES)); + static const OUString strNo(DBA_RES(STR_VALUE_NO)); + OUString sValue; + // Read out the fields + switch( nColId ) + { + case FIELD_NAME: + sValue = pFieldDescr->GetName(); + break; + + case FIELD_TYPE: + if ( pFieldDescr->getTypeInfo() ) + sValue = pFieldDescr->getTypeInfo()->aUIName; + break; + + case COLUMN_DESCRIPTION: + sValue = pFieldDescr->GetDescription(); + break; + case HELP_TEXT: + sValue = pFieldDescr->GetHelpText(); + break; + + case FIELD_PROPERTY_DEFAULT: + return pFieldDescr->GetControlDefault(); + + case FIELD_PROPERTY_REQUIRED: + sValue = pFieldDescr->GetIsNullable() == ColumnValue::NULLABLE ? strYes : strNo; + break; + + case FIELD_PROPERTY_TEXTLEN: + case FIELD_PROPERTY_LENGTH: + sValue = OUString::number(pFieldDescr->GetPrecision()); + break; + + case FIELD_PROPERTY_NUMTYPE: + OSL_FAIL("OTableEditorCtrl::GetCellData: invalid column!"); + break; + + case FIELD_PROPERTY_AUTOINC: + sValue = pFieldDescr->IsAutoIncrement() ? strYes : strNo; + break; + + case FIELD_PROPERTY_SCALE: + sValue = OUString::number(pFieldDescr->GetScale()); + break; + + case FIELD_PROPERTY_BOOL_DEFAULT: + sValue = GetView()->GetDescWin()->BoolStringUI(::comphelper::getString(pFieldDescr->GetControlDefault())); + break; + + case FIELD_PROPERTY_FORMAT: + sValue = OUString::number(pFieldDescr->GetFormatKey()); + break; + } + + return Any(sValue); +} + +OUString OTableEditorCtrl::GetCellText( sal_Int32 nRow, sal_uInt16 nColId ) const +{ + OUString sCellText; + const_cast< OTableEditorCtrl* >( this )->GetCellData( nRow, nColId ) >>= sCellText; + return sCellText; +} + +sal_uInt32 OTableEditorCtrl::GetTotalCellWidth(sal_Int32 nRow, sal_uInt16 nColId) +{ + return GetTextWidth(GetCellText(nRow, nColId)) + 2 * GetTextWidth("0"); +} + +OFieldDescription* OTableEditorCtrl::GetFieldDescr( sal_Int32 nRow ) +{ + std::vector< std::shared_ptr<OTableRow> >::size_type nListCount( + m_pRowList->size()); + if( (nRow<0) || (sal::static_int_cast< unsigned long >(nRow)>=nListCount) ) + { + OSL_FAIL("(nRow<0) || (nRow>=nListCount)"); + return nullptr; + } + std::shared_ptr<OTableRow> pRow = (*m_pRowList)[ nRow ]; + if( !pRow ) + return nullptr; + return pRow->GetActFieldDescr(); +} + +bool OTableEditorCtrl::IsCutAllowed() +{ + bool bIsCutAllowed = (GetView()->getController().isAddAllowed() && GetView()->getController().isDropAllowed()) || + GetView()->getController().isAlterAllowed(); + + if (bIsCutAllowed) + { + int nStartPos, nEndPos; + switch(m_eChildFocus) + { + case DESCRIPTION: + { + weld::Entry& rEntry = pDescrCell->get_widget(); + bIsCutAllowed = rEntry.get_selection_bounds(nStartPos, nEndPos); + break; + } + case HELPTEXT: + { + weld::Entry& rEntry = pHelpTextCell->get_widget(); + bIsCutAllowed = rEntry.get_selection_bounds(nStartPos, nEndPos); + break; + } + case NAME: + { + weld::Entry& rEntry = pNameCell->get_widget(); + bIsCutAllowed = rEntry.get_selection_bounds(nStartPos, nEndPos); + break; + } + case ROW: + bIsCutAllowed = IsCopyAllowed(); + break; + default: + bIsCutAllowed = false; + break; + } + } + + return bIsCutAllowed; +} + +bool OTableEditorCtrl::IsCopyAllowed() +{ + bool bIsCopyAllowed = false; + int nStartPos, nEndPos; + if (m_eChildFocus == DESCRIPTION ) + { + weld::Entry& rEntry = pDescrCell->get_widget(); + bIsCopyAllowed = rEntry.get_selection_bounds(nStartPos, nEndPos); + } + else if(HELPTEXT == m_eChildFocus ) + { + weld::Entry& rEntry = pHelpTextCell->get_widget(); + bIsCopyAllowed = rEntry.get_selection_bounds(nStartPos, nEndPos); + } + else if(m_eChildFocus == NAME) + { + weld::Entry& rEntry = pNameCell->get_widget(); + bIsCopyAllowed = rEntry.get_selection_bounds(nStartPos, nEndPos); + } + else if(m_eChildFocus == ROW) + { + Reference<XPropertySet> xTable = GetView()->getController().getTable(); + if( !GetSelectRowCount() || (xTable.is() && ::comphelper::getString(xTable->getPropertyValue(PROPERTY_TYPE)) == "VIEW")) + return false; + + // If one of the selected rows is empty, Copy is not possible + std::shared_ptr<OTableRow> pRow; + tools::Long nIndex = FirstSelectedRow(); + while( nIndex != SFX_ENDOFSELECTION ) + { + pRow = (*m_pRowList)[nIndex]; + if( !pRow->GetActFieldDescr() ) + return false; + + nIndex = NextSelectedRow(); + } + + bIsCopyAllowed = true; + } + + return bIsCopyAllowed; +} + +bool OTableEditorCtrl::IsPasteAllowed() const +{ + bool bAllowed = GetView()->getController().isAddAllowed(); + if ( bAllowed ) + { + TransferableDataHelper aTransferData(TransferableDataHelper::CreateFromSystemClipboard(GetParent())); + bool bRowFormat = aTransferData.HasFormat(SotClipboardFormatId::SBA_TABED); + if ( m_eChildFocus == ROW ) + bAllowed = bRowFormat; + else + bAllowed = !bRowFormat && aTransferData.HasFormat(SotClipboardFormatId::STRING); + } + + return bAllowed; +} + +void OTableEditorCtrl::cut() +{ + if(m_eChildFocus == NAME) + { + if(GetView()->getController().isAlterAllowed()) + { + SaveData(-1,FIELD_NAME); + pNameCell->get_widget().cut_clipboard(); + CellModified(-1,FIELD_NAME); + } + } + else if(m_eChildFocus == DESCRIPTION) + { + if(GetView()->getController().isAlterAllowed()) + { + SaveData(-1,COLUMN_DESCRIPTION); + pDescrCell->get_widget().cut_clipboard(); + CellModified(-1,COLUMN_DESCRIPTION); + } + } + else if(HELPTEXT == m_eChildFocus ) + { + if(GetView()->getController().isAlterAllowed()) + { + SaveData(-1,HELP_TEXT); + pHelpTextCell->get_widget().cut_clipboard(); + CellModified(-1,HELP_TEXT); + } + } + else if(m_eChildFocus == ROW) + { + if (nCutEvent) + Application::RemoveUserEvent(nCutEvent); + nCutEvent = Application::PostUserEvent(LINK(this, OTableEditorCtrl, DelayedCut), nullptr, true); + } +} + +void OTableEditorCtrl::copy() +{ + if (GetSelectRowCount()) + OTableRowView::copy(); + else if(m_eChildFocus == NAME) + { + weld::Entry& rEntry = pNameCell->get_widget(); + rEntry.copy_clipboard(); + } + else if(HELPTEXT == m_eChildFocus ) + { + weld::Entry& rEntry = pHelpTextCell->get_widget(); + rEntry.copy_clipboard(); + } + else if(m_eChildFocus == DESCRIPTION ) + { + weld::Entry& rEntry = pDescrCell->get_widget(); + rEntry.copy_clipboard(); + } +} + +void OTableEditorCtrl::paste() +{ + TransferableDataHelper aTransferData(TransferableDataHelper::CreateFromSystemClipboard(GetParent())); + if(aTransferData.HasFormat(SotClipboardFormatId::SBA_TABED)) + { + if( nPasteEvent ) + Application::RemoveUserEvent( nPasteEvent ); + nPasteEvent = Application::PostUserEvent( LINK(this, OTableEditorCtrl, DelayedPaste), nullptr, true ); + } + else if(m_eChildFocus == NAME) + { + if(GetView()->getController().isAlterAllowed()) + { + pNameCell->get_widget().paste_clipboard(); + CellModified(); + } + } + else if(HELPTEXT == m_eChildFocus ) + { + if(GetView()->getController().isAlterAllowed()) + { + pHelpTextCell->get_widget().paste_clipboard(); + CellModified(); + } + } + else if(m_eChildFocus == DESCRIPTION) + { + if(GetView()->getController().isAlterAllowed()) + { + pDescrCell->get_widget().paste_clipboard(); + CellModified(); + } + } +} + +bool OTableEditorCtrl::IsDeleteAllowed() +{ + + return GetSelectRowCount() != 0 && GetView()->getController().isDropAllowed(); +} + +bool OTableEditorCtrl::IsInsertNewAllowed( sal_Int32 nRow ) +{ + + bool bInsertNewAllowed = GetView()->getController().isAddAllowed(); + // If fields can be added, Paste in the new fields + if (bInsertNewAllowed && !GetView()->getController().isDropAllowed()) + { + SetDataPtr(nRow); + if( GetActRow()->IsReadOnly() ) + return false; + } + + return bInsertNewAllowed; +} + +bool OTableEditorCtrl::IsPrimaryKeyAllowed() +{ + if( !GetSelectRowCount() ) + return false; + + OTableController& rController = GetView()->getController(); + if ( !rController.getSdbMetaData().supportsPrimaryKeys() ) + return false; + + Reference<XPropertySet> xTable = rController.getTable(); + // Key must not be changed + // This applies only if the table is not new and not a css::sdbcx::View. Otherwise no DROP is executed + + if(xTable.is() && ::comphelper::getString(xTable->getPropertyValue(PROPERTY_TYPE)) == "VIEW") + return false; + // If there is an empty field, no primary key + // The entry is only permitted if + // - there are no empty entries in the selection + // - No Memo or Image entries + // - DROP is not permitted (see above) and the column is not Required (not null flag is not set). + tools::Long nIndex = FirstSelectedRow(); + std::shared_ptr<OTableRow> pRow; + while( nIndex != SFX_ENDOFSELECTION ) + { + pRow = (*m_pRowList)[nIndex]; + OFieldDescription* pFieldDescr = pRow->GetActFieldDescr(); + if(!pFieldDescr) + return false; + else + { + // Memo and Image fields cannot be primary keys + // or if the column cannot be dropped and the Required flag is not set + // or if a css::sdbcx::View is available and the Required flag is not set + const TOTypeInfoSP& pTypeInfo = pFieldDescr->getTypeInfo(); + if( pTypeInfo->nSearchType == ColumnSearch::NONE + || (pFieldDescr->IsNullable() && pRow->IsReadOnly()) + ) + return false; + } + + nIndex = NextSelectedRow(); + } + + return true; +} + +void OTableEditorCtrl::Command(const CommandEvent& rEvt) +{ + switch (rEvt.GetCommand()) + { + case CommandEventId::ContextMenu: + { + Point aMenuPos( rEvt.GetMousePosPixel() ); + if (!rEvt.IsMouseEvent()) + { + if ( 1 == GetSelectColumnCount() ) + { + sal_uInt16 nSelId = GetColumnId( + sal::static_int_cast< sal_uInt16 >( + FirstSelectedColumn() ) ); + ::tools::Rectangle aColRect( GetFieldRectPixel( 0, nSelId, false ) ); + + aMenuPos = aColRect.TopCenter(); + } + else if ( GetSelectRowCount() > 0 ) + { + ::tools::Rectangle aColRect( GetFieldRectPixel( FirstSelectedRow(), HANDLE_ID ) ); + + aMenuPos = aColRect.TopCenter(); + } + else + { + OTableRowView::Command(rEvt); + return; + } + } + + // Show the Context menu + if( !IsReadOnly() ) + { + sal_uInt16 nColId = GetColumnId(GetColumnAtXPosPixel(aMenuPos.X())); + sal_Int32 nRow = GetRowAtYPosPixel(aMenuPos.Y()); + + if ( HANDLE_ID != nColId ) + { + if ( nRow < 0 && nColId != BROWSER_INVALIDID ) + { // hit the header + if ( 3 != nColId ) + { // 3 would mean the last column, and this last column is auto-sized + if ( !IsColumnSelected( nColId ) ) + SelectColumnId( nColId ); + + ::tools::Rectangle aRect(aMenuPos, Size(1, 1)); + weld::Window* pPopupParent = weld::GetPopupParent(*this, aRect); + std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(pPopupParent, "dbaccess/ui/querycolmenu.ui")); + std::unique_ptr<weld::Menu> xContextMenu(xBuilder->weld_menu("menu")); + xContextMenu->remove("delete"); + xContextMenu->remove("separator"); + if (xContextMenu->popup_at_rect(pPopupParent, aRect) == "width") + adjustBrowseBoxColumnWidth( this, nColId ); + } + } + } + else + { + ::tools::Rectangle aRect(aMenuPos, Size(1, 1)); + weld::Window* pPopupParent = weld::GetPopupParent(*this, aRect); + std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(pPopupParent, "dbaccess/ui/tabledesignrowmenu.ui")); + std::unique_ptr<weld::Menu> xContextMenu(xBuilder->weld_menu("menu")); + + if (!IsCutAllowed()) + xContextMenu->remove("cut"); + if (!IsCopyAllowed()) + xContextMenu->remove("copy"); + if (!IsPasteAllowed()) + xContextMenu->remove("paste"); + if (!IsDeleteAllowed()) + xContextMenu->remove("delete"); + if (!IsPrimaryKeyAllowed()) + xContextMenu->remove("primarykey"); + if (!IsInsertNewAllowed(nRow)) + xContextMenu->remove("insert"); + xContextMenu->set_active("primarykey", IsRowSelected(GetCurRow()) && IsPrimaryKey()); + + if( SetDataPtr(m_nDataPos) ) + pDescrWin->SaveData( pActRow->GetActFieldDescr() ); + + // All actions which change the number of rows must be run asynchronously + // otherwise there may be problems between the Context menu and the Browser + m_nDataPos = GetCurRow(); + OString sIdent = xContextMenu->popup_at_rect(pPopupParent, aRect); + if (sIdent == "cut") + cut(); + else if (sIdent == "copy") + copy(); + else if (sIdent == "paste") + paste(); + else if (sIdent == "delete") + { + if( nDeleteEvent ) + Application::RemoveUserEvent( nDeleteEvent ); + nDeleteEvent = Application::PostUserEvent( LINK(this, OTableEditorCtrl, DelayedDelete), nullptr, true ); + } + else if (sIdent == "insert") + { + if( nInsNewRowsEvent ) + Application::RemoveUserEvent( nInsNewRowsEvent ); + nInsNewRowsEvent = Application::PostUserEvent( LINK(this, OTableEditorCtrl, DelayedInsNewRows), nullptr, true ); + } + else if (sIdent == "primarykey") + { + SetPrimaryKey( !IsPrimaryKey() ); + } + } + } + } + break; + default: + OTableRowView::Command(rEvt); + } + +} + +IMPL_LINK_NOARG( OTableEditorCtrl, DelayedCut, void*, void ) +{ + nCutEvent = nullptr; + OTableRowView::cut(); +} + +IMPL_LINK_NOARG( OTableEditorCtrl, DelayedPaste, void*, void ) +{ + nPasteEvent = nullptr; + + sal_Int32 nPastePosition = GetView()->getController().getFirstEmptyRowPosition(); + if ( !GetView()->getController().getTable().is() ) + nPastePosition = GetSelectRowCount() ? FirstSelectedRow() : GetCurRow(); + + if (!IsInsertNewAllowed(nPastePosition)) + { // Insertion is not allowed, only appending, so test if there are full cells after the PastePosition + + auto aIter = std::find_if(m_pRowList->rbegin(), m_pRowList->rend(), [](const std::shared_ptr<OTableRow>& rxRow) { + return rxRow && rxRow->GetActFieldDescr() && !rxRow->GetActFieldDescr()->GetName().isEmpty(); }); + auto nFreeFromPos = static_cast<sal_Int32>(std::distance(aIter, m_pRowList->rend())); // from here on there are only empty rows + if (nPastePosition < nFreeFromPos) // if at least one PastePosition is full, go right to the end + nPastePosition = nFreeFromPos; + } + + OTableRowView::Paste( nPastePosition ); + SetNoSelection(); + GoToRow( nPastePosition ); +} + +IMPL_LINK_NOARG( OTableEditorCtrl, DelayedDelete, void*, void ) +{ + nDeleteEvent = nullptr; + DeleteRows(); +} + +IMPL_LINK_NOARG( OTableEditorCtrl, DelayedInsNewRows, void*, void ) +{ + nInsNewRowsEvent = nullptr; + sal_Int32 nPastePosition = GetView()->getController().getFirstEmptyRowPosition(); + if ( !GetView()->getController().getTable().is() ) + nPastePosition = GetSelectRowCount() ? FirstSelectedRow() : m_nDataPos; + + InsertNewRows( nPastePosition ); + SetNoSelection(); + GoToRow( nPastePosition ); +} + +void OTableEditorCtrl::AdjustFieldDescription(OFieldDescription* _pFieldDesc, + MultiSelection& _rMultiSel, + sal_Int32 _nPos, + bool _bSet, + bool _bPrimaryKey) +{ + _pFieldDesc->SetPrimaryKey( _bPrimaryKey ); + if(!_bSet && _pFieldDesc->getTypeInfo()->bNullable) + { + _pFieldDesc->SetIsNullable(ColumnValue::NO_NULLS); + _pFieldDesc->SetControlDefault(Any()); + } + if ( _pFieldDesc->IsAutoIncrement() && !_bPrimaryKey ) + { + OTableController& rController = GetView()->getController(); + if ( rController.isAutoIncrementPrimaryKey() ) + { + _pFieldDesc->SetAutoIncrement(false); + } + } + // update field description + pDescrWin->DisplayData(_pFieldDesc); + + _rMultiSel.Insert( _nPos ); + _rMultiSel.Select( _nPos ); +} + +void OTableEditorCtrl::SetPrimaryKey( bool bSet ) +{ + // Delete any existing Primary Keys + MultiSelection aDeletedPrimKeys; + aDeletedPrimKeys.SetTotalRange( Range(0,GetRowCount()) ); + + sal_Int32 nRow = 0; + for (auto const& row : *m_pRowList) + { + OFieldDescription* pFieldDescr = row->GetActFieldDescr(); + if( pFieldDescr && row->IsPrimaryKey() && (!bSet || !IsRowSelected(nRow)) ) + { + AdjustFieldDescription(pFieldDescr,aDeletedPrimKeys,nRow,bSet,false); + } + ++nRow; + } + + // Set the primary keys of the marked rows + MultiSelection aInsertedPrimKeys; + aInsertedPrimKeys.SetTotalRange( Range(0,GetRowCount()) ); + if( bSet ) + { + tools::Long nIndex = FirstSelectedRow(); + while( nIndex != SFX_ENDOFSELECTION ) + { + // Set the key + std::shared_ptr<OTableRow> pRow = (*m_pRowList)[nIndex]; + OFieldDescription* pFieldDescr = pRow->GetActFieldDescr(); + if(pFieldDescr) + AdjustFieldDescription(pFieldDescr,aInsertedPrimKeys,nIndex,false,true); + + nIndex = NextSelectedRow(); + } + } + + GetUndoManager().AddUndoAction( std::make_unique<OPrimKeyUndoAct>(this, aDeletedPrimKeys, aInsertedPrimKeys) ); + + // Invalidate the handle-columns + InvalidateHandleColumn(); + + // Set the TableDocSh's ModifyFlag + GetView()->getController().setModified( true ); + InvalidateFeatures(); +} + +bool OTableEditorCtrl::IsPrimaryKey() +{ + // Are all marked fields part of the Primary Key ? + tools::Long nPrimaryKeys = 0; + sal_Int32 nRow=0; + for (auto const& row : *m_pRowList) + { + if( IsRowSelected(nRow) && !row->IsPrimaryKey() ) + return false; + if( row->IsPrimaryKey() ) + ++nPrimaryKeys; + ++nRow; + } + + // Are there any unselected fields that are part of the Key ? + return GetSelectRowCount() == nPrimaryKeys; +} + +void OTableEditorCtrl::SwitchType( const TOTypeInfoSP& _pType ) +{ + // if there is no assigned field name + sal_Int32 nRow(GetCurRow()); + OFieldDescription* pActFieldDescr = GetFieldDescr( nRow ); + if( pActFieldDescr ) + // Store the old description + pDescrWin->SaveData( pActFieldDescr ); + + if ( nRow < 0 || o3tl::make_unsigned(nRow) > m_pRowList->size() ) + return; + // Show the new description + std::shared_ptr<OTableRow> pRow = (*m_pRowList)[nRow]; + pRow->SetFieldType( _pType, true ); + if ( _pType ) + { + weld::ComboBox& rTypeList = pTypeCell->get_widget(); + const sal_Int32 nCurrentlySelected = rTypeList.get_active(); + + if ( ( nCurrentlySelected == -1 ) + || ( GetView()->getController().getTypeInfo( nCurrentlySelected ) != _pType ) + ) + { + sal_Int32 nEntryPos = 0; + const OTypeInfoMap& rTypeInfo = GetView()->getController().getTypeInfo(); + for (auto const& elem : rTypeInfo) + { + if(elem.second == _pType) + break; + ++nEntryPos; + } + if (nEntryPos < rTypeList.get_count()) + rTypeList.set_active(nEntryPos); + } + } + + pActFieldDescr = pRow->GetActFieldDescr(); + if (pActFieldDescr != nullptr && !pActFieldDescr->GetFormatKey()) + { + sal_Int32 nFormatKey = ::dbtools::getDefaultNumberFormat( pActFieldDescr->GetType(), + pActFieldDescr->GetScale(), + pActFieldDescr->IsCurrency(), + Reference< XNumberFormatTypes>(GetView()->getController().getNumberFormatter()->getNumberFormatsSupplier()->getNumberFormats(),UNO_QUERY), + GetView()->getLocale()); + + pActFieldDescr->SetFormatKey(nFormatKey); + } + + pDescrWin->DisplayData( pActFieldDescr ); +} + +OTableDesignView* OTableEditorCtrl::GetView() const +{ + return m_pView; +} + +void OTableEditorCtrl::DeactivateCell(bool bUpdate) +{ + OTableRowView::DeactivateCell(bUpdate); + // now we have to deactivate the field description + sal_Int32 nRow(GetCurRow()); + if (pDescrWin) + pDescrWin->SetReadOnly(bReadOnly || !SetDataPtr(nRow) || GetActRow()->IsReadOnly()); +} + +bool OTableEditorCtrl::PreNotify( NotifyEvent& rNEvt ) +{ + if (rNEvt.GetType() == MouseNotifyEvent::GETFOCUS) + { + if( pHelpTextCell && pHelpTextCell->HasChildPathFocus() ) + m_eChildFocus = HELPTEXT; + else if( pDescrCell && pDescrCell->HasChildPathFocus() ) + m_eChildFocus = DESCRIPTION; + else if(pNameCell && pNameCell->HasChildPathFocus() ) + m_eChildFocus = NAME; + else + m_eChildFocus = ROW; + } + + return OTableRowView::PreNotify(rNEvt); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/tabledesign/TEditControl.hxx b/dbaccess/source/ui/tabledesign/TEditControl.hxx new file mode 100644 index 000000000..7b1d46781 --- /dev/null +++ b/dbaccess/source/ui/tabledesign/TEditControl.hxx @@ -0,0 +1,204 @@ +/* -*- 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 . + */ +#pragma once + +#include <TableDesignControl.hxx> +#include <TableDesignView.hxx> +#include "TableFieldDescWin.hxx" +#include <TableRow.hxx> +#include <TypeInfo.hxx> + +class Edit; +class SfxUndoManager; +namespace dbaui +{ + class OSQLNameEditControl; + + class OTableEditorCtrl : public OTableRowView + { + enum ChildFocusState + { + HELPTEXT, + DESCRIPTION, + NAME, + ROW, + NONE + }; + + std::vector< std::shared_ptr<OTableRow> >* m_pRowList; + + VclPtr<OTableDesignView> m_pView; + VclPtr<OSQLNameEditControl> pNameCell; + VclPtr<::svt::ListBoxControl> pTypeCell; + VclPtr<::svt::EditControl> pHelpTextCell; + VclPtr<::svt::EditControl> pDescrCell; + OTableFieldDescWin* pDescrWin; // properties of one column + + std::shared_ptr<OTableRow> pActRow; + + ImplSVEvent * nCutEvent; + ImplSVEvent * nPasteEvent; + ImplSVEvent * nDeleteEvent; + ImplSVEvent * nInsNewRowsEvent; + ImplSVEvent * nInvalidateTypeEvent; + ChildFocusState m_eChildFocus; + + tools::Long nOldDataPos; + + bool bReadOnly; + + // helper class + class ClipboardInvalidator final + { + private: + AutoTimer m_aInvalidateTimer; + VclPtr<OTableEditorCtrl> m_pOwner; + + public: + explicit ClipboardInvalidator(OTableEditorCtrl*); + ~ClipboardInvalidator(); + void Stop(); + + private: + DECL_LINK(OnInvalidate, Timer*, void); + }; + + friend class OTableEditorCtrl::ClipboardInvalidator; + + ClipboardInvalidator m_aInvalidate; + + protected: + virtual void Command( const CommandEvent& rEvt ) override; + virtual bool SeekRow(sal_Int32 nRow) override; + virtual void PaintCell(OutputDevice& rDev, const tools::Rectangle& rRect, + sal_uInt16 nColumnId ) const override; + + virtual void CursorMoved() override; + virtual RowStatus GetRowStatus(sal_Int32 nRow) const override; + + virtual ::svt::CellController* GetController(sal_Int32 nRow, sal_uInt16 nCol) override; + virtual void InitController(::svt::CellControllerRef& rController, sal_Int32 nRow, sal_uInt16 nCol) override; + + virtual void CellModified() override; + virtual bool SaveModified() override; // is called before changing a cell (false prevents change) + + virtual OUString GetCellText(sal_Int32 nRow, sal_uInt16 nColId) const override; + virtual sal_uInt32 GetTotalCellWidth(sal_Int32 nRow, sal_uInt16 nColId) override; + + virtual void CopyRows() override; + virtual void InsertRows( sal_Int32 nRow ) override; + virtual void DeleteRows() override; + virtual void InsertNewRows( sal_Int32 nRow ) override; + + virtual bool IsPrimaryKeyAllowed() override; + virtual bool IsInsertNewAllowed( sal_Int32 nRow ) override; + virtual bool IsDeleteAllowed() override; + + void ClearModified(); + + void SetPrimaryKey( bool bSet ); + bool IsPrimaryKey(); + + public: + explicit OTableEditorCtrl(vcl::Window* pParentWin, OTableDesignView* pView); + virtual ~OTableEditorCtrl() override; + virtual void dispose() override; + virtual bool CursorMoving(sal_Int32 nNewRow, sal_uInt16 nNewCol) override; + SfxUndoManager& GetUndoManager() const; + + void SetDescrWin( OTableFieldDescWin* pWin ) + { + pDescrWin = pWin; + if (pDescrWin && pActRow) + pDescrWin->DisplayData(pActRow->GetActFieldDescr()); + } + void SaveCurRow(); + void SwitchType( const TOTypeInfoSP& _pType ); + + /// force displaying of the given row + void DisplayData( sal_Int32 nRow ); + + virtual void SetCellData( sal_Int32 nRow, sal_uInt16 nColId, const TOTypeInfoSP& _pTypeInfo ) override; + virtual void SetCellData( sal_Int32 nRow, sal_uInt16 nColId, const css::uno::Any& _rSaveData ) override; + virtual css::uno::Any GetCellData( sal_Int32 nRow, sal_uInt16 nColId ) override; + virtual void SetControlText( sal_Int32 nRow, sal_uInt16 nColId, const OUString& rText ) override; + + virtual OTableDesignView* GetView() const override; + + std::vector< std::shared_ptr<OTableRow> >* GetRowList(){ return m_pRowList; } + + const std::shared_ptr<OTableRow>& GetActRow() const { return pActRow; } + void CellModified( sal_Int32 nRow, sal_uInt16 nColId ); + void SetReadOnly( bool bRead ); + + virtual void Init() override; + virtual void DeactivateCell(bool bUpdate = true) override; + + bool IsCutAllowed(); + bool IsCopyAllowed(); + bool IsPasteAllowed() const; + bool IsReadOnly() const { return bReadOnly;} + OFieldDescription* GetFieldDescr( sal_Int32 nRow ); + + // Window overrides + virtual bool PreNotify( NotifyEvent& rNEvt ) override; + + // IClipboardTest + virtual bool isCutAllowed() override { return IsCutAllowed(); } + virtual bool isCopyAllowed() override { return IsCopyAllowed(); } + virtual bool isPasteAllowed() override { return IsPasteAllowed(); } + + virtual void cut() override; + virtual void copy() override; + virtual void paste() override; + + private: + DECL_LINK( DelayedCut, void*, void ); + DECL_LINK( DelayedPaste, void*, void ); + DECL_LINK( DelayedDelete, void*, void ); + DECL_LINK( DelayedInsNewRows, void*, void ); + DECL_LINK( InvalidateFieldType, void*, void ); + + void InitCellController(); + sal_Int32 HasFieldName( std::u16string_view rFieldName ); + OUString GenerateName( const OUString& rName ); + bool SetDataPtr( sal_Int32 nRow ); + + void SaveData(sal_Int32 nRow, sal_uInt16 nColumnId); + /** AdjustFieldDescription set the needed values for the description + @param _pFieldDesc the field description where to set the values + @param _rMultiSel contains the positions which changed for undo/redo + @param _nPos the current position + @param _bSet should a key be set + @param _bPrimaryKey which value should the pkey have + */ + void AdjustFieldDescription( OFieldDescription* _pFieldDesc, + MultiSelection& _rMultiSel, + sal_Int32 _nPos, + bool _bSet, + bool _bPrimaryKey); + /** InvalidateFeatures invalidates the slots SID_UNDO | SID_REDO | SID_SAVEDOC + */ + void InvalidateFeatures(); + + void resetType(); + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/tabledesign/TableController.cxx b/dbaccess/source/ui/tabledesign/TableController.cxx new file mode 100644 index 000000000..07fe30a91 --- /dev/null +++ b/dbaccess/source/ui/tabledesign/TableController.cxx @@ -0,0 +1,1495 @@ +/* -*- 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 <FieldDescriptions.hxx> +#include "TEditControl.hxx" +#include <TableController.hxx> +#include <TableDesignView.hxx> +#include <TableRow.hxx> +#include <TypeInfo.hxx> +#include <UITools.hxx> +#include <browserids.hxx> +#include <core_resource.hxx> +#include <strings.hrc> +#include <strings.hxx> +#include <defaultobjectnamecheck.hxx> +#include <dlgsave.hxx> +#include <indexdialog.hxx> +#include <sqlmessage.hxx> + +#include <com/sun/star/frame/XTitleChangeListener.hpp> +#include <com/sun/star/sdb/CommandType.hpp> +#include <com/sun/star/sdb/SQLContext.hpp> +#include <com/sun/star/sdbc/ColumnValue.hpp> +#include <com/sun/star/sdbc/SQLWarning.hpp> +#include <com/sun/star/sdbcx/KeyType.hpp> +#include <com/sun/star/sdbcx/XAlterTable.hpp> +#include <com/sun/star/sdbcx/XAppend.hpp> +#include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp> +#include <com/sun/star/sdbcx/XDrop.hpp> +#include <com/sun/star/sdbcx/XIndexesSupplier.hpp> +#include <com/sun/star/sdbcx/XTablesSupplier.hpp> + +#include <connectivity/dbexception.hxx> +#include <connectivity/dbtools.hxx> +#include <connectivity/dbmetadata.hxx> +#include <cppuhelper/exc_hlp.hxx> +#include <tools/diagnose_ex.h> +#include <vcl/svapp.hxx> +#include <vcl/weld.hxx> +#include <o3tl/string_view.hxx> + +#include <algorithm> +#include <functional> +#include <set> + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +org_openoffice_comp_dbu_OTableDesign_get_implementation( + css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& ) +{ + return cppu::acquire(new ::dbaui::OTableController(context)); +} + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::io; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::frame; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::sdb; +using namespace ::com::sun::star::ui; +using namespace ::com::sun::star::util; +using namespace ::dbtools; +using namespace ::dbaui; +using namespace ::comphelper; + +// number of columns when creating it from scratch +#define NEWCOLS 128 + +namespace +{ + void dropTable(const Reference<XNameAccess>& _rxTable,const OUString& _sTableName) + { + if ( _rxTable->hasByName(_sTableName) ) + { + Reference<XDrop> xNameCont(_rxTable,UNO_QUERY); + OSL_ENSURE(xNameCont.is(),"No drop interface for tables!"); + if ( xNameCont.is() ) + xNameCont->dropByName(_sTableName); + } + } +} + +OUString SAL_CALL OTableController::getImplementationName() +{ + return "org.openoffice.comp.dbu.OTableDesign"; +} + +Sequence< OUString> OTableController::getSupportedServiceNames() +{ + return { "com.sun.star.sdb.TableDesign" }; +} + +OTableController::OTableController(const Reference< XComponentContext >& _rM) : OTableController_BASE(_rM) + ,m_sTypeNames(DBA_RES(STR_TABLEDESIGN_DBFIELDTYPES)) + ,m_bAllowAutoIncrementValue(false) + ,m_bNew(true) +{ + + InvalidateAll(); + m_pTypeInfo = std::make_shared<OTypeInfo>(); + m_pTypeInfo->aUIName = m_sTypeNames.getToken(TYPE_OTHER, ';'); +} + +OTableController::~OTableController() +{ + m_aTypeInfoIndex.clear(); + m_aTypeInfo.clear(); + +} + +void OTableController::startTableListening() +{ + Reference< XComponent > xComponent(m_xTable, UNO_QUERY); + if (xComponent.is()) + xComponent->addEventListener(static_cast<XModifyListener*>(this)); +} + +void OTableController::stopTableListening() +{ + Reference< XComponent > xComponent(m_xTable, UNO_QUERY); + if (xComponent.is()) + xComponent->removeEventListener(static_cast<XModifyListener*>(this)); +} + +void OTableController::disposing() +{ + OTableController_BASE::disposing(); + clearView(); + + m_vRowList.clear(); +} + +FeatureState OTableController::GetState(sal_uInt16 _nId) const +{ + FeatureState aReturn; + // disabled automatically + + switch (_nId) + { + case ID_BROWSER_CLOSE: + aReturn.bEnabled = true; + break; + case ID_BROWSER_EDITDOC: + aReturn.bChecked = isEditable(); + aReturn.bEnabled = true; + break; + case ID_BROWSER_SAVEDOC: + aReturn.bEnabled = isEditable() && std::any_of(m_vRowList.begin(),m_vRowList.end(),std::mem_fn(&OTableRow::isValid)); + break; + case ID_BROWSER_SAVEASDOC: + aReturn.bEnabled = isConnected() && isEditable(); + if ( aReturn.bEnabled ) + { + aReturn.bEnabled = std::any_of(m_vRowList.begin(),m_vRowList.end(), + std::mem_fn(&OTableRow::isValid)); + } + break; + + case ID_BROWSER_CUT: + aReturn.bEnabled = isEditable() && getView() && static_cast<OTableDesignView*>(getView())->isCutAllowed(); + break; + case ID_BROWSER_COPY: + aReturn.bEnabled = getView() && static_cast<OTableDesignView*>(getView())->isCopyAllowed(); + break; + case ID_BROWSER_PASTE: + aReturn.bEnabled = isEditable() && getView() && static_cast<OTableDesignView*>(getView())->isPasteAllowed(); + break; + case SID_INDEXDESIGN: + aReturn.bEnabled = + ( ( ((!m_bNew && impl_isModified()) || impl_isModified()) + || Reference< XIndexesSupplier >(m_xTable, UNO_QUERY).is() + ) + && isConnected() + ); + if ( aReturn.bEnabled ) + { + aReturn.bEnabled = std::any_of(m_vRowList.begin(),m_vRowList.end(), + std::mem_fn(&OTableRow::isValid)); + } + break; + default: + aReturn = OTableController_BASE::GetState(_nId); + } + return aReturn; +} + +void OTableController::Execute(sal_uInt16 _nId, const Sequence< PropertyValue >& aArgs) +{ + switch(_nId) + { + case ID_BROWSER_EDITDOC: + setEditable(!isEditable()); + static_cast<OTableDesignView*>(getView())->setReadOnly(!isEditable()); + InvalidateFeature(ID_BROWSER_SAVEDOC); + InvalidateFeature(ID_BROWSER_PASTE); + InvalidateFeature(SID_BROWSER_CLEAR_QUERY); + break; + case ID_BROWSER_SAVEASDOC: + doSaveDoc(true); + break; + case ID_BROWSER_SAVEDOC: + static_cast<OTableDesignView*>(getView())->GetEditorCtrl()->SaveCurRow(); + doSaveDoc(false); + break; + case ID_BROWSER_CUT: + static_cast<OTableDesignView*>(getView())->cut(); + break; + case ID_BROWSER_COPY: + static_cast<OTableDesignView*>(getView())->copy(); + break; + case ID_BROWSER_PASTE: + static_cast<OTableDesignView*>(getView())->paste(); + break; + case SID_INDEXDESIGN: + doEditIndexes(); + break; + default: + OTableController_BASE::Execute(_nId,aArgs); + } + InvalidateFeature(_nId); +} + +bool OTableController::doSaveDoc(bool _bSaveAs) +{ + if (!isConnected()) + reconnect(true); // ask the user for a new connection + Reference<XTablesSupplier> xTablesSup(getConnection(),UNO_QUERY); + + if (!xTablesSup.is()) + { + OUString aMessage(DBA_RES(STR_TABLEDESIGN_CONNECTION_MISSING)); + OSQLWarningBox aWarning(getFrameWeld(), aMessage); + aWarning.run(); + return false; + } + + // check if a column exists + // TODO + + Reference<XNameAccess> xTables; + OUString sCatalog, sSchema; + + bool bNew = m_sName.isEmpty(); + bNew = bNew || m_bNew || _bSaveAs; + + try + { + xTables = xTablesSup->getTables(); + OSL_ENSURE(xTables.is(),"The tables can't be null!"); + bNew = bNew || (xTables.is() && !xTables->hasByName(m_sName)); + + // first we need a name for our query so ask the user + if(bNew) + { + OUString aName = DBA_RES(STR_TBL_TITLE); + OUString aDefaultName = aName.getToken(0,' '); + aDefaultName = ::dbtools::createUniqueName(xTables,aDefaultName); + + DynamicTableOrQueryNameCheck aNameChecker( getConnection(), CommandType::TABLE ); + OSaveAsDlg aDlg(getFrameWeld(), CommandType::TABLE, getORB(), getConnection(), aDefaultName, aNameChecker, SADFlags::NONE); + if (aDlg.run() != RET_OK) + return false; + + m_sName = aDlg.getName(); + sCatalog = aDlg.getCatalog(); + sSchema = aDlg.getSchema(); + } + + // did we get a name + if(m_sName.isEmpty()) + return false; + } + catch(Exception&) + { + OSL_FAIL("OTableController::doSaveDoc: nothing is expected to happen here!"); + } + + bool bAlter = false; + bool bError = false; + SQLExceptionInfo aInfo; + try + { + // check the columns for double names + if(!checkColumns(bNew || !xTables->hasByName(m_sName))) + { + return false; + } + + Reference<XPropertySet> xTable; + if(bNew || !xTables->hasByName(m_sName)) // just to make sure the table already exists + { + dropTable(xTables,m_sName); + + Reference<XDataDescriptorFactory> xFact(xTables,UNO_QUERY); + OSL_ENSURE(xFact.is(),"OTableController::doSaveDoc: No XDataDescriptorFactory available!"); + xTable = xFact->createDataDescriptor(); + OSL_ENSURE(xTable.is(),"OTableController::doSaveDoc: Create query failed!"); + // to set the name is only allowed when the query is new + xTable->setPropertyValue(PROPERTY_CATALOGNAME,Any(sCatalog)); + xTable->setPropertyValue(PROPERTY_SCHEMANAME,Any(sSchema)); + xTable->setPropertyValue(PROPERTY_NAME,Any(m_sName)); + + // now append the columns + Reference<XColumnsSupplier> xColSup(xTable,UNO_QUERY); + appendColumns(xColSup,bNew); + // now append the primary key + Reference<XKeysSupplier> xKeySup(xTable,UNO_QUERY); + appendPrimaryKey(xKeySup,bNew); + } + // now set the properties + if(bNew) + { + Reference<XAppend> xAppend(xTables,UNO_QUERY); + OSL_ENSURE(xAppend.is(),"OTableController::doSaveDoc: No XAppend Interface!"); + xAppend->appendByDescriptor(xTable); + + assignTable(); + if(!m_xTable.is()) // correct name and try again + { + // it can be that someone inserted new data for us + m_sName = ::dbtools::composeTableName( getConnection()->getMetaData(), xTable, ::dbtools::EComposeRule::InDataManipulation, false ); + assignTable(); + } + // now check if our datasource has set a tablefilter and if append the new table name to it + ::dbaui::appendToFilter(getConnection(), m_sName, getORB(), getFrameWeld()); // we are not interested in the return value + Reference< frame::XTitleChangeListener> xEventListener(impl_getTitleHelper_throw(),UNO_QUERY); + if ( xEventListener.is() ) + { + frame::TitleChangedEvent aEvent; + xEventListener->titleChanged(aEvent); + } + releaseNumberForComponent(); + } + else if(m_xTable.is()) + { + bAlter = true; + alterColumns(); + } + reSyncRows(); + } + catch(const SQLContext& e) + { + aInfo = SQLExceptionInfo(e); + } + catch(const SQLWarning& e) + { + aInfo = SQLExceptionInfo(e); + } + catch(const SQLException& e) + { + aInfo = SQLExceptionInfo(e); + } + catch(const ElementExistException& ) + { + OUString sText( DBA_RES( STR_NAME_ALREADY_EXISTS ) ); + sText = sText.replaceFirst( "#" , m_sName); + OSQLMessageBox aDlg(getFrameWeld(), DBA_RES( STR_ERROR_DURING_CREATION ), sText, MessBoxStyle::Ok, MessageType::Error); + aDlg.run(); + bError = true; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + bError = true; + } + + if ( aInfo.isValid() ) + aInfo.prepend( DBA_RES( STR_TABLEDESIGN_SAVE_ERROR ) ); + showError(aInfo); + + if (aInfo.isValid() || bError) + { + if(!bAlter || bNew) + { + m_sName.clear(); + stopTableListening(); + m_xTable = nullptr; + } + } + return ! (aInfo.isValid() || bError); +} + +void OTableController::doEditIndexes() +{ + // table needs to be saved before editing indexes + if (m_bNew || isModified()) + { + std::unique_ptr<weld::MessageDialog> xAsk(Application::CreateMessageDialog(getFrameWeld(), + VclMessageType::Question, VclButtonsType::YesNo, + DBA_RES(STR_QUERY_SAVE_TABLE_EDIT_INDEXES))); + if (RET_YES != xAsk->run()) + return; + + if (!doSaveDoc(false)) + return; + + OSL_ENSURE(!m_bNew && !isModified(), "OTableController::doEditIndexes: what the hell did doSaveDoc do?"); + } + + Reference< XNameAccess > xIndexes; // will be the keys of the table + Sequence< OUString > aFieldNames; // will be the column names of the table + try + { + // get the keys + Reference< XIndexesSupplier > xIndexesSupp(m_xTable, UNO_QUERY); + if (xIndexesSupp.is()) + { + xIndexes = xIndexesSupp->getIndexes(); + OSL_ENSURE(xIndexes.is(), "OTableController::doEditIndexes: no keys got from the indexes supplier!"); + } + else + OSL_FAIL("OTableController::doEditIndexes: should never have reached this (no indexes supplier)!"); + + // get the field names + Reference< XColumnsSupplier > xColSupp(m_xTable, UNO_QUERY); + OSL_ENSURE(xColSupp.is(), "OTableController::doEditIndexes: no columns supplier!"); + if (xColSupp.is()) + { + Reference< XNameAccess > xCols = xColSupp->getColumns(); + OSL_ENSURE(xCols.is(), "OTableController::doEditIndexes: no columns!"); + if (xCols.is()) + aFieldNames = xCols->getElementNames(); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + if (!xIndexes.is()) + return; + + DbaIndexDialog aDialog(getFrameWeld(), aFieldNames, xIndexes, getConnection(), getORB()); + if (RET_OK != aDialog.run()) + return; + +} + +void OTableController::impl_initialize() +{ + try + { + OTableController_BASE::impl_initialize(); + + const NamedValueCollection& rArguments( getInitParams() ); + + rArguments.get_ensureType( PROPERTY_CURRENTTABLE, m_sName ); + + // read autoincrement value set in the datasource + ::dbaui::fillAutoIncrementValue(getDataSource(),m_bAllowAutoIncrementValue,m_sAutoIncrementValue); + + assignTable(); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + try + { + ::dbaui::fillTypeInfo(getConnection(),m_sTypeNames,m_aTypeInfo,m_aTypeInfoIndex); // fill the needed type information + } + catch(const SQLException&) + { + OSQLWarningBox aWarning(getFrameWeld(), DBA_RES( STR_NO_TYPE_INFO_AVAILABLE)); + aWarning.run(); + throw; + } + try + { + loadData(); // fill the column information from the table + getView()->initialize(); // show the windows and fill with our information + ClearUndoManager(); + setModified(false); // and we are not modified yet + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +bool OTableController::Construct(vcl::Window* pParent) +{ + setView( VclPtr<OTableDesignView>::Create( pParent, getORB(), *this ) ); + OTableController_BASE::Construct(pParent); + return true; +} + +sal_Bool SAL_CALL OTableController::suspend(sal_Bool /*_bSuspend*/) +{ + if ( getBroadcastHelper().bInDispose || getBroadcastHelper().bDisposed ) + return true; + + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( getMutex() ); + if ( getView() && getView()->IsInModalMode() ) + return false; + if ( getView() ) + static_cast<OTableDesignView*>(getView())->GrabFocus(); + bool bCheck = true; + if ( isModified() ) + { + if ( std::any_of(m_vRowList.begin(),m_vRowList.end(), + std::mem_fn(&OTableRow::isValid)) ) + { + std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(getFrameWeld(), "dbaccess/ui/tabledesignsavemodifieddialog.ui")); + std::unique_ptr<weld::MessageDialog> xQuery(xBuilder->weld_message_dialog("TableDesignSaveModifiedDialog")); + switch (xQuery->run()) + { + case RET_YES: + Execute(ID_BROWSER_SAVEDOC,Sequence<PropertyValue>()); + if ( isModified() ) + bCheck = false; // when we save the table this must be false else some press cancel + break; + case RET_CANCEL: + bCheck = false; + break; + default: + break; + } + } + else if ( !m_bNew ) + { + std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(getFrameWeld(), "dbaccess/ui/deleteallrowsdialog.ui")); + std::unique_ptr<weld::MessageDialog> xQuery(xBuilder->weld_message_dialog("DeleteAllRowsDialog")); + switch (xQuery->run()) + { + case RET_YES: + { + try + { + Reference<XTablesSupplier> xTablesSup(getConnection(),UNO_QUERY); + Reference<XNameAccess> xTables = xTablesSup->getTables(); + dropTable(xTables,m_sName); + } + catch(const Exception&) + { + OSL_FAIL("OTableController::suspend: nothing is expected to happen here!"); + } + + } + break; + case RET_CANCEL: + bCheck = false; + break; + default: + break; + } + } + } + + return bCheck; +} + +void OTableController::describeSupportedFeatures() +{ + OSingleDocumentController::describeSupportedFeatures(); + + implDescribeSupportedFeature( ".uno:Redo", ID_BROWSER_REDO, CommandGroup::EDIT ); + implDescribeSupportedFeature( ".uno:Save", ID_BROWSER_SAVEDOC, CommandGroup::EDIT ); + implDescribeSupportedFeature( ".uno:Undo", ID_BROWSER_UNDO, CommandGroup::EDIT ); + implDescribeSupportedFeature( ".uno:NewDoc", SID_NEWDOC, CommandGroup::DOCUMENT ); + implDescribeSupportedFeature( ".uno:SaveAs", ID_BROWSER_SAVEASDOC, CommandGroup::DOCUMENT ); + implDescribeSupportedFeature( ".uno:DBIndexDesign", SID_INDEXDESIGN, CommandGroup::APPLICATION ); + implDescribeSupportedFeature( ".uno:EditDoc", ID_BROWSER_EDITDOC, CommandGroup::EDIT ); + implDescribeSupportedFeature( ".uno:GetUndoStrings", SID_GETUNDOSTRINGS ); + implDescribeSupportedFeature( ".uno:GetRedoStrings", SID_GETREDOSTRINGS ); +} + +void OTableController::impl_onModifyChanged() +{ + OSingleDocumentController::impl_onModifyChanged(); + InvalidateFeature( SID_INDEXDESIGN ); +} + +void SAL_CALL OTableController::disposing( const EventObject& _rSource ) +{ + if ( _rSource.Source == m_xTable ) + { // some deleted our table so we have a new one + stopTableListening(); + m_xTable = nullptr; + m_bNew = true; + setModified(true); + } + else + OTableController_BASE::disposing( _rSource ); +} + +void OTableController::losingConnection( ) +{ + // let the base class do its reconnect + OTableController_BASE::losingConnection( ); + + // remove from the table + Reference< XComponent > xComponent(m_xTable, UNO_QUERY); + if (xComponent.is()) + { + Reference<XEventListener> xEvtL( static_cast< ::cppu::OWeakObject*>(this), UNO_QUERY); + xComponent->removeEventListener(xEvtL); + } + stopTableListening(); + m_xTable = nullptr; + assignTable(); + if(!m_xTable.is()) + { + m_bNew = true; + setModified(true); + } + InvalidateAll(); +} + +TOTypeInfoSP OTableController::getTypeInfoByType(sal_Int32 _nDataType) const +{ + return queryTypeInfoByType(_nDataType,m_aTypeInfo); +} + +void OTableController::appendColumns(Reference<XColumnsSupplier> const & _rxColSup, bool _bNew, bool _bKeyColumns) +{ + try + { + // now append the columns + OSL_ENSURE(_rxColSup.is(),"No columns supplier"); + if(!_rxColSup.is()) + return; + Reference<XNameAccess> xColumns = _rxColSup->getColumns(); + OSL_ENSURE(xColumns.is(),"No columns"); + Reference<XDataDescriptorFactory> xColumnFactory(xColumns,UNO_QUERY); + + Reference<XAppend> xAppend(xColumns,UNO_QUERY); + OSL_ENSURE(xAppend.is(),"No XAppend Interface!"); + + for (auto const& row : m_vRowList) + { + OSL_ENSURE(row,"OTableRow is null!"); + OFieldDescription* pField = row->GetActFieldDescr(); + if ( !pField || (!_bNew && row->IsReadOnly() && !_bKeyColumns) ) + continue; + + Reference<XPropertySet> xColumn; + if(pField->IsPrimaryKey() || !_bKeyColumns) + xColumn = xColumnFactory->createDataDescriptor(); + if(xColumn.is()) + { + if(!_bKeyColumns) + ::dbaui::setColumnProperties(xColumn,pField); + else + xColumn->setPropertyValue(PROPERTY_NAME,Any(pField->GetName())); + + xAppend->appendByDescriptor(xColumn); + xColumn = nullptr; + // now only the settings are missing + if(xColumns->hasByName(pField->GetName())) + { + xColumns->getByName(pField->GetName()) >>= xColumn; + if(xColumn.is()) + pField->copyColumnSettingsTo(xColumn); + } + else + { + OSL_FAIL("OTableController::appendColumns: invalid field name!"); + } + + } + } + } + catch(const SQLException& ) + { + showError( SQLExceptionInfo( ::cppu::getCaughtException() ) ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +void OTableController::appendPrimaryKey(Reference<XKeysSupplier> const & _rxSup, bool _bNew) +{ + if(!_rxSup.is()) + return; // the database doesn't support keys + + OSL_ENSURE(_rxSup.is(),"No XKeysSupplier!"); + Reference<XIndexAccess> xKeys = _rxSup->getKeys(); + Reference<XPropertySet> xProp; + if (!xKeys.is()) + return; + const sal_Int32 nCount = xKeys->getCount(); + for(sal_Int32 i=0;i< nCount ;++i) + { + xKeys->getByIndex(i) >>= xProp; + sal_Int32 nKeyType = 0; + xProp->getPropertyValue(PROPERTY_TYPE) >>= nKeyType; + if(KeyType::PRIMARY == nKeyType) + { + return; // primary key already exists after appending a column + } + } + Reference<XDataDescriptorFactory> xKeyFactory(xKeys,UNO_QUERY); + OSL_ENSURE(xKeyFactory.is(),"No XDataDescriptorFactory Interface!"); + if ( !xKeyFactory.is() ) + return; + Reference<XAppend> xAppend(xKeyFactory,UNO_QUERY); + OSL_ENSURE(xAppend.is(),"No XAppend Interface!"); + + Reference<XPropertySet> xKey = xKeyFactory->createDataDescriptor(); + OSL_ENSURE(xKey.is(),"Key is null!"); + xKey->setPropertyValue(PROPERTY_TYPE,Any(KeyType::PRIMARY)); + + Reference<XColumnsSupplier> xColSup(xKey,UNO_QUERY); + if(xColSup.is()) + { + appendColumns(xColSup,_bNew,true); + Reference<XNameAccess> xColumns = xColSup->getColumns(); + if(xColumns->hasElements()) + xAppend->appendByDescriptor(xKey); + } +} + +void OTableController::loadData() +{ + // if the data structure already exists, empty it + m_vRowList.clear(); + + std::shared_ptr<OTableRow> pTabEdRow; + Reference< XDatabaseMetaData> xMetaData = getMetaData( ); + // fill data structure with data from DataDefinitionObject + if(m_xTable.is() && xMetaData.is()) + { + Reference<XColumnsSupplier> xColSup(m_xTable,UNO_QUERY); + OSL_ENSURE(xColSup.is(),"No XColumnsSupplier!"); + Reference<XNameAccess> xColumns = xColSup->getColumns(); + // ReadOnly-Flag + // For Drop no row may be editable + // For Add only the empty rows may be editable + // For Add and Drop all rows can be edited + // sal_Bool bReadOldRow = xMetaData->supportsAlterTableWithAddColumn() && xMetaData->supportsAlterTableWithDropColumn(); + bool bIsAlterAllowed = isAlterAllowed(); + + const Sequence<OUString> aColNames = xColumns->getElementNames(); + for(const OUString& rColumn : aColNames) + { + Reference<XPropertySet> xColumn; + xColumns->getByName(rColumn) >>= xColumn; + sal_Int32 nType = 0; + sal_Int32 nScale = 0; + sal_Int32 nPrecision = 0; + sal_Int32 nNullable = 0; + sal_Int32 nFormatKey = 0; + sal_Int32 nAlign = 0; + + bool bIsAutoIncrement = false, bIsCurrency = false; + OUString sName,sDescription,sTypeName,sHelpText; + Any aControlDefault; + + // get the properties from the column + xColumn->getPropertyValue(PROPERTY_NAME) >>= sName; + xColumn->getPropertyValue(PROPERTY_TYPENAME) >>= sTypeName; + xColumn->getPropertyValue(PROPERTY_ISNULLABLE) >>= nNullable; + xColumn->getPropertyValue(PROPERTY_ISAUTOINCREMENT) >>= bIsAutoIncrement; + xColumn->getPropertyValue(PROPERTY_ISCURRENCY) >>= bIsCurrency; + xColumn->getPropertyValue(PROPERTY_TYPE) >>= nType; + xColumn->getPropertyValue(PROPERTY_SCALE) >>= nScale; + xColumn->getPropertyValue(PROPERTY_PRECISION) >>= nPrecision; + xColumn->getPropertyValue(PROPERTY_DESCRIPTION) >>= sDescription; + + if(xColumn->getPropertySetInfo()->hasPropertyByName(PROPERTY_HELPTEXT)) + xColumn->getPropertyValue(PROPERTY_HELPTEXT) >>= sHelpText; + + if(xColumn->getPropertySetInfo()->hasPropertyByName(PROPERTY_CONTROLDEFAULT)) + aControlDefault = xColumn->getPropertyValue(PROPERTY_CONTROLDEFAULT); + if(xColumn->getPropertySetInfo()->hasPropertyByName(PROPERTY_FORMATKEY)) + xColumn->getPropertyValue(PROPERTY_FORMATKEY) >>= nFormatKey; + if(xColumn->getPropertySetInfo()->hasPropertyByName(PROPERTY_ALIGN)) + xColumn->getPropertyValue(PROPERTY_ALIGN) >>= nAlign; + + pTabEdRow = std::make_shared<OTableRow>(); + pTabEdRow->SetReadOnly(!bIsAlterAllowed); + // search for type + bool bForce; + TOTypeInfoSP pTypeInfo = ::dbaui::getTypeInfoFromType(m_aTypeInfo,nType,sTypeName,"x",nPrecision,nScale,bIsAutoIncrement,bForce); + if ( !pTypeInfo ) + pTypeInfo = m_pTypeInfo; + pTabEdRow->SetFieldType( pTypeInfo, bForce ); + + OFieldDescription* pActFieldDescr = pTabEdRow->GetActFieldDescr(); + OSL_ENSURE(pActFieldDescr, "OTableController::loadData: invalid field description generated by the table row!"); + if ( pActFieldDescr ) + { + pActFieldDescr->SetName(sName); + pActFieldDescr->SetFormatKey(nFormatKey); + pActFieldDescr->SetDescription(sDescription); + pActFieldDescr->SetHelpText(sHelpText); + pActFieldDescr->SetAutoIncrement(bIsAutoIncrement); + pActFieldDescr->SetHorJustify(dbaui::mapTextJustify(nAlign)); + pActFieldDescr->SetCurrency(bIsCurrency); + + // special data + pActFieldDescr->SetIsNullable(nNullable); + pActFieldDescr->SetControlDefault(aControlDefault); + pActFieldDescr->SetPrecision(nPrecision); + pActFieldDescr->SetScale(nScale); + } + m_vRowList.push_back( pTabEdRow); + } + // fill the primary key information + Reference<XNameAccess> xKeyColumns = getKeyColumns(); + if(xKeyColumns.is()) + { + const Sequence<OUString> aKeyColumnNames = xKeyColumns->getElementNames(); + for(const OUString& rKeyColumn : aKeyColumnNames) + { + for(std::shared_ptr<OTableRow> const& pRow : m_vRowList) + { + if(pRow->GetActFieldDescr()->GetName() == rKeyColumn) + { + pRow->SetPrimaryKey(true); + break; + } + } + } + } + } + + // fill empty rows + + OTypeInfoMap::const_iterator aTypeIter = m_aTypeInfo.find(DataType::VARCHAR); + if(aTypeIter == m_aTypeInfo.end()) + aTypeIter = m_aTypeInfo.begin(); + + OSL_ENSURE(aTypeIter != m_aTypeInfo.end(),"We have no type information!"); + + bool bReadRow = !isAddAllowed(); + for(sal_Int32 i=m_vRowList.size(); i < NEWCOLS; i++ ) + { + pTabEdRow = std::make_shared<OTableRow>(); + pTabEdRow->SetReadOnly(bReadRow); + m_vRowList.push_back( pTabEdRow); + } +} + +Reference<XNameAccess> OTableController::getKeyColumns() const +{ + return getPrimaryKeyColumns_throw(m_xTable); +} + +bool OTableController::checkColumns(bool _bNew) +{ + bool bOk = true; + bool bFoundPKey = false; + Reference< XDatabaseMetaData > xMetaData = getMetaData( ); + DatabaseMetaData aMetaData( getConnection() ); + + ::comphelper::UStringMixEqual bCase(!xMetaData.is() || xMetaData->supportsMixedCaseQuotedIdentifiers()); + std::vector< std::shared_ptr<OTableRow> >::const_iterator aIter = m_vRowList.begin(); + std::vector< std::shared_ptr<OTableRow> >::const_iterator aEnd = m_vRowList.end(); + for(;aIter != aEnd;++aIter) + { + OFieldDescription* pFieldDesc = (*aIter)->GetActFieldDescr(); + if (pFieldDesc && !pFieldDesc->GetName().isEmpty()) + { + bFoundPKey |= (*aIter)->IsPrimaryKey(); + // first check for duplicate names + bool bDuplicateNameFound = std::any_of(aIter+1, aEnd, + [&bCase, &pFieldDesc](const std::shared_ptr<OTableRow>& rxRow) { + OFieldDescription* pCompareDesc = rxRow->GetActFieldDescr(); + return pCompareDesc && bCase(pCompareDesc->GetName(),pFieldDesc->GetName()); + }); + if (bDuplicateNameFound) + { + OUString strMessage = DBA_RES(STR_TABLEDESIGN_DUPLICATE_NAME); + strMessage = strMessage.replaceFirst("$column$", pFieldDesc->GetName()); + OSQLWarningBox aWarning(getFrameWeld(), strMessage); + aWarning.run(); + return false; + } + } + } + if ( _bNew && !bFoundPKey && aMetaData.supportsPrimaryKeys() ) + { + OUString sTitle(DBA_RES(STR_TABLEDESIGN_NO_PRIM_KEY_HEAD)); + OUString sMsg(DBA_RES(STR_TABLEDESIGN_NO_PRIM_KEY)); + OSQLMessageBox aBox(getFrameWeld(), sTitle,sMsg, MessBoxStyle::YesNoCancel | MessBoxStyle::DefaultYes); + + switch (aBox.run()) + { + case RET_YES: + { + auto pNewRow = std::make_shared<OTableRow>(); + TOTypeInfoSP pTypeInfo = ::dbaui::queryPrimaryKeyType(m_aTypeInfo); + if ( !pTypeInfo ) + break; + + pNewRow->SetFieldType( pTypeInfo ); + OFieldDescription* pActFieldDescr = pNewRow->GetActFieldDescr(); + + pActFieldDescr->SetAutoIncrement(false); + pActFieldDescr->SetIsNullable(ColumnValue::NO_NULLS); + + pActFieldDescr->SetName( createUniqueName("ID" )); + pActFieldDescr->SetPrimaryKey( true ); + m_vRowList.insert(m_vRowList.begin(),pNewRow); + + static_cast<OTableDesignView*>(getView())->GetEditorCtrl()->Invalidate(); + static_cast<OTableDesignView*>(getView())->GetEditorCtrl()->RowInserted(0); + } + break; + case RET_CANCEL: + bOk = false; + break; + } + } + return bOk; +} + +void OTableController::alterColumns() +{ + Reference<XColumnsSupplier> xColSup(m_xTable,UNO_QUERY_THROW); + + Reference<XNameAccess> xColumns = xColSup->getColumns(); + Reference<XIndexAccess> xIdxColumns(xColumns,UNO_QUERY_THROW); + OSL_ENSURE(xColumns.is(),"No columns"); + if ( !xColumns.is() ) + return; + Reference<XAlterTable> xAlter(m_xTable,UNO_QUERY); // can be null + + sal_Int32 nColumnCount = xIdxColumns->getCount(); + Reference<XDrop> xDrop(xColumns,UNO_QUERY); // can be null + Reference<XAppend> xAppend(xColumns,UNO_QUERY); // can be null + Reference<XDataDescriptorFactory> xColumnFactory(xColumns,UNO_QUERY); // can be null + + bool bReload = false; // refresh the data + + // contains all columns names which are already handled those which are not in the list will be deleted + Reference< XDatabaseMetaData> xMetaData = getMetaData( ); + + std::set<OUString, comphelper::UStringMixLess> aColumns( + comphelper::UStringMixLess( + !xMetaData.is() + || xMetaData->supportsMixedCaseQuotedIdentifiers())); + std::vector< std::shared_ptr<OTableRow> >::const_iterator aIter = m_vRowList.begin(); + std::vector< std::shared_ptr<OTableRow> >::const_iterator aEnd = m_vRowList.end(); + // first look for columns where something other than the name changed + for(sal_Int32 nPos = 0;aIter != aEnd;++aIter,++nPos) + { + OSL_ENSURE(*aIter,"OTableRow is null!"); + OFieldDescription* pField = (*aIter)->GetActFieldDescr(); + if ( !pField ) + continue; + if ( (*aIter)->IsReadOnly() ) + { + aColumns.insert(pField->GetName()); + continue; + } + + Reference<XPropertySet> xColumn; + if ( xColumns->hasByName(pField->GetName()) ) + { + aColumns.insert(pField->GetName()); + xColumns->getByName(pField->GetName()) >>= xColumn; + OSL_ENSURE(xColumn.is(),"Column is null!"); + + sal_Int32 nType=0,nPrecision=0,nScale=0,nNullable=0; + bool bAutoIncrement = false; + OUString sTypeName,sDescription; + + xColumn->getPropertyValue(PROPERTY_TYPE) >>= nType; + xColumn->getPropertyValue(PROPERTY_PRECISION) >>= nPrecision; + xColumn->getPropertyValue(PROPERTY_SCALE) >>= nScale; + xColumn->getPropertyValue(PROPERTY_ISNULLABLE) >>= nNullable; + xColumn->getPropertyValue(PROPERTY_ISAUTOINCREMENT) >>= bAutoIncrement; + xColumn->getPropertyValue(PROPERTY_DESCRIPTION) >>= sDescription; + + try { xColumn->getPropertyValue(PROPERTY_TYPENAME) >>= sTypeName; } + catch( const Exception& ) + { + OSL_FAIL( "no TypeName property?!" ); + // since this is a last minute fix for #i41785#, I want to be on the safe side, + // and catch errors here as early as possible (instead of the whole process of altering + // the columns failing) + // Normally, sdbcx::Column objects are expected to have a TypeName property + } + + // check if something changed + if((nType != pField->GetType() || + sTypeName != pField->GetTypeName() || + (nPrecision != pField->GetPrecision() && nPrecision ) || + nScale != pField->GetScale() || + nNullable != pField->GetIsNullable() || + sDescription != pField->GetDescription() || + bAutoIncrement != pField->IsAutoIncrement())&& + xColumnFactory.is()) + { + Reference<XPropertySet> xNewColumn = xColumnFactory->createDataDescriptor(); + ::dbaui::setColumnProperties(xNewColumn,pField); + // first try to alter the column + bool bNotOk = false; + try + { + // first try if we can alter the column + if(xAlter.is()) + xAlter->alterColumnByName(pField->GetName(),xNewColumn); + } + catch(const SQLException&) + { + if(xDrop.is() && xAppend.is()) + { + OUString aMessage( DBA_RES( STR_TABLEDESIGN_ALTER_ERROR ) ); + aMessage = aMessage.replaceFirst( "$column$", pField->GetName() ); + + SQLExceptionInfo aError( ::cppu::getCaughtException() ); + OSQLWarningBox aMsg(getFrameWeld(), aMessage, MessBoxStyle::YesNo | MessBoxStyle::DefaultYes , &aError); + bNotOk = aMsg.run() == RET_YES; + } + else + throw; + } + // if something went wrong or we can't alter columns + // drop and append a new one + if((!xAlter.is() || bNotOk) && xDrop.is() && xAppend.is()) + { + xDrop->dropByName(pField->GetName()); + try + { + xAppend->appendByDescriptor(xNewColumn); + } + catch(const SQLException&) + { // an error occurred so we try to reactivate the old one + xAppend->appendByDescriptor(xColumn); + throw; + } + } + // exceptions are caught outside + xNewColumn = nullptr; + if(xColumns->hasByName(pField->GetName())) + xColumns->getByName(pField->GetName()) >>= xColumn; + bReload = true; + } + + } + else if(xColumnFactory.is() && xAlter.is() && nPos < nColumnCount) + { // we can't find the column so we could try it with the index before we drop and append a new column + try + { + Reference<XPropertySet> xNewColumn = xColumnFactory->createDataDescriptor(); + ::dbaui::setColumnProperties(xNewColumn,pField); + xAlter->alterColumnByIndex(nPos,xNewColumn); + if(xColumns->hasByName(pField->GetName())) + { // ask for the append by name + aColumns.insert(pField->GetName()); + xColumns->getByName(pField->GetName()) >>= xColumn; + if(xColumn.is()) + pField->copyColumnSettingsTo(xColumn); + } + else + { + OSL_FAIL("OTableController::alterColumns: invalid column (2)!"); + } + } + catch(const SQLException&) + { // we couldn't alter the column so we have to add new columns + SQLExceptionInfo aError( ::cppu::getCaughtException() ); + bReload = true; + if(xDrop.is() && xAppend.is()) + { + OUString aMessage(DBA_RES(STR_TABLEDESIGN_ALTER_ERROR)); + aMessage = aMessage.replaceFirst("$column$",pField->GetName()); + OSQLWarningBox aMsg(getFrameWeld(), aMessage, MessBoxStyle::YesNo | MessBoxStyle::DefaultYes, &aError); + if (aMsg.run() != RET_YES) + { + Reference<XPropertySet> xNewColumn(xIdxColumns->getByIndex(nPos),UNO_QUERY_THROW); + OUString sName; + xNewColumn->getPropertyValue(PROPERTY_NAME) >>= sName; + aColumns.insert(sName); + aColumns.insert(pField->GetName()); + continue; + } + } + else + throw; + } + } + else + bReload = true; + } + // alter column settings + + // first look for columns where something other than the name changed + for (auto const& row : m_vRowList) + { + OSL_ENSURE(row,"OTableRow is null!"); + OFieldDescription* pField = row->GetActFieldDescr(); + if ( !pField ) + continue; + if ( row->IsReadOnly() ) + { + aColumns.insert(pField->GetName()); + continue; + } + + Reference<XPropertySet> xColumn; + if ( xColumns->hasByName(pField->GetName()) ) + { + xColumns->getByName(pField->GetName()) >>= xColumn; + Reference<XPropertySetInfo> xInfo = xColumn->getPropertySetInfo(); + if ( xInfo->hasPropertyByName(PROPERTY_HELPTEXT) ) + xColumn->setPropertyValue(PROPERTY_HELPTEXT,Any(pField->GetHelpText())); + + if(xInfo->hasPropertyByName(PROPERTY_CONTROLDEFAULT)) + xColumn->setPropertyValue(PROPERTY_CONTROLDEFAULT,pField->GetControlDefault()); + if(xInfo->hasPropertyByName(PROPERTY_FORMATKEY)) + xColumn->setPropertyValue(PROPERTY_FORMATKEY,Any(pField->GetFormatKey())); + if(xInfo->hasPropertyByName(PROPERTY_ALIGN)) + xColumn->setPropertyValue(PROPERTY_ALIGN,Any(dbaui::mapTextAlign(pField->GetHorJustify()))); + } + } + // second drop all columns which could be found by name + Reference<XNameAccess> xKeyColumns = getKeyColumns(); + // now we have to look for the columns who could be deleted + if ( xDrop.is() ) + { + const Sequence<OUString> aColNames = xColumns->getElementNames(); + for(const OUString& rColumnName : aColNames) + { + if(aColumns.find(rColumnName) == aColumns.end()) // found a column to delete + { + if(xKeyColumns.is() && xKeyColumns->hasByName(rColumnName)) // check if this column is a member of the primary key + { + OUString aMsgT(DBA_RES(STR_TBL_COLUMN_IS_KEYCOLUMN)); + aMsgT = aMsgT.replaceFirst("$column$",rColumnName); + OUString aTitle(DBA_RES(STR_TBL_COLUMN_IS_KEYCOLUMN_TITLE)); + OSQLMessageBox aMsg(getFrameWeld(), aTitle, aMsgT, MessBoxStyle::YesNo| MessBoxStyle::DefaultYes); + if (aMsg.run() == RET_YES) + { + xKeyColumns = nullptr; + dropPrimaryKey(); + } + else + { + bReload = true; + continue; + } + } + try + { + xDrop->dropByName(rColumnName); + } + catch (const SQLException&) + { + OUString sError( DBA_RES( STR_TABLEDESIGN_COULD_NOT_DROP_COL ) ); + sError = sError.replaceFirst( "$column$", rColumnName ); + + SQLException aNewException; + aNewException.Message = sError; + aNewException.SQLState = "S1000"; + aNewException.NextException = ::cppu::getCaughtException(); + + throw aNewException; + } + } + } + } + + // third append the new columns + for(const auto& rxRow : m_vRowList) + { + OSL_ENSURE(rxRow,"OTableRow is null!"); + OFieldDescription* pField = rxRow->GetActFieldDescr(); + if ( !pField || rxRow->IsReadOnly() || aColumns.find(pField->GetName()) != aColumns.end() ) + continue; + + Reference<XPropertySet> xColumn; + if(!xColumns->hasByName(pField->GetName())) + { + if(xColumnFactory.is() && xAppend.is()) + {// column not found by its name so we assume it is new + // Column is new + xColumn = xColumnFactory->createDataDescriptor(); + ::dbaui::setColumnProperties(xColumn,pField); + xAppend->appendByDescriptor(xColumn); + if(xColumns->hasByName(pField->GetName())) + { // ask for the append by name + aColumns.insert(pField->GetName()); + xColumns->getByName(pField->GetName()) >>= xColumn; + if(xColumn.is()) + pField->copyColumnSettingsTo(xColumn); + } + else + { + OSL_FAIL("OTableController::alterColumns: invalid column!"); + } + } + } + } + + // check if we have to do something with the primary key + bool bNeedDropKey = false; + bool bNeedAppendKey = false; + if ( xKeyColumns.is() ) + { + for(const auto& rxRow : m_vRowList) + { + OSL_ENSURE(rxRow,"OTableRow is null!"); + OFieldDescription* pField = rxRow->GetActFieldDescr(); + if ( !pField ) + continue; + + if ( pField->IsPrimaryKey() + && !xKeyColumns->hasByName( pField->GetName() ) + ) + { // new primary key column inserted which isn't already in the columns selection + bNeedDropKey = bNeedAppendKey = true; + break; + } + else if ( !pField->IsPrimaryKey() + && xKeyColumns->hasByName( pField->GetName() ) + ) + { // found a column which currently is in the primary key, but is marked not to be anymore + bNeedDropKey = bNeedAppendKey = true; + break; + } + } + } + else + { // no primary key available so we check if we should create one + bNeedAppendKey = true; + } + + if ( bNeedDropKey && xKeyColumns.is() && xKeyColumns->getElementNames().hasElements() ) + dropPrimaryKey(); + + if ( bNeedAppendKey ) + { + Reference< XKeysSupplier > xKeySup( m_xTable, UNO_QUERY ); + appendPrimaryKey( xKeySup ,false); + } + + reSyncRows(); + + if ( bReload ) + reload(); +} + +void OTableController::dropPrimaryKey() +{ + SQLExceptionInfo aInfo; + try + { + Reference<XKeysSupplier> xKeySup(m_xTable,UNO_QUERY); + Reference<XIndexAccess> xKeys; + if(xKeySup.is()) + xKeys = xKeySup->getKeys(); + + if(xKeys.is()) + { + Reference<XPropertySet> xProp; + for(sal_Int32 i=0;i< xKeys->getCount();++i) + { + xProp.set(xKeys->getByIndex(i),UNO_QUERY); + sal_Int32 nKeyType = 0; + xProp->getPropertyValue(PROPERTY_TYPE) >>= nKeyType; + if(KeyType::PRIMARY == nKeyType) + { + Reference<XDrop> xDrop(xKeys,UNO_QUERY); + xDrop->dropByIndex(i); // delete the key + break; + } + } + } + } + catch(const SQLContext& e) + { + aInfo = SQLExceptionInfo(e); + } + catch(const SQLWarning& e) + { + aInfo = SQLExceptionInfo(e); + } + catch(const SQLException& e) + { + aInfo = SQLExceptionInfo(e); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + showError(aInfo); +} + +void OTableController::assignTable() +{ + // get the table + if(m_sName.isEmpty()) + return; + + Reference<XNameAccess> xNameAccess; + Reference<XTablesSupplier> xSup(getConnection(),UNO_QUERY); + if(!xSup.is()) + return; + + xNameAccess = xSup->getTables(); + OSL_ENSURE(xNameAccess.is(),"no nameaccess for the queries!"); + + if(!xNameAccess->hasByName(m_sName)) + return; + + Reference<XPropertySet> xProp(xNameAccess->getByName(m_sName), css::uno::UNO_QUERY); + if (!xProp.is()) + return; + + m_xTable = xProp; + startTableListening(); + + // check if we set the table editable + Reference<XDatabaseMetaData> xMeta = getConnection()->getMetaData(); + setEditable( xMeta.is() && !xMeta->isReadOnly() && (isAlterAllowed() || isDropAllowed() || isAddAllowed()) ); + if(!isEditable()) + { + for( const auto& rTableRow : m_vRowList ) + { + rTableRow->SetReadOnly(); + } + } + m_bNew = false; + // be notified when the table is in disposing + InvalidateAll(); +} + +bool OTableController::isAddAllowed() const +{ + Reference<XColumnsSupplier> xColsSup(m_xTable,UNO_QUERY); + bool bAddAllowed = !m_xTable.is(); + if(xColsSup.is()) + bAddAllowed = Reference<XAppend>(xColsSup->getColumns(),UNO_QUERY).is(); + + try + { + Reference< XDatabaseMetaData > xMetaData = getMetaData( ); + bAddAllowed = bAddAllowed || ( xMetaData.is() && xMetaData->supportsAlterTableWithAddColumn()); + } + catch(Exception&) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + bAddAllowed = false; + } + + return bAddAllowed; +} + +bool OTableController::isDropAllowed() const +{ + Reference<XColumnsSupplier> xColsSup(m_xTable,UNO_QUERY); + bool bDropAllowed = !m_xTable.is(); + if(xColsSup.is()) + { + Reference<XNameAccess> xNameAccess = xColsSup->getColumns(); + bDropAllowed = Reference<XDrop>(xNameAccess,UNO_QUERY).is() && xNameAccess->hasElements(); + } + + Reference< XDatabaseMetaData> xMetaData = getMetaData( ); + bDropAllowed = bDropAllowed || ( xMetaData.is() && xMetaData->supportsAlterTableWithDropColumn()); + + return bDropAllowed; +} + +bool OTableController::isAlterAllowed() const +{ + bool bAllowed(!m_xTable.is() || Reference<XAlterTable>(m_xTable,UNO_QUERY).is()); + return bAllowed; +} + +void OTableController::reSyncRows() +{ + bool bAlterAllowed = isAlterAllowed(); + bool bAddAllowed = isAddAllowed(); + for (auto const& row : m_vRowList) + { + OSL_ENSURE(row,"OTableRow is null!"); + OFieldDescription* pField = row->GetActFieldDescr(); + if ( pField ) + row->SetReadOnly(!bAlterAllowed); + else + row->SetReadOnly(!bAddAllowed); + + } + static_cast<OTableDesignView*>(getView())->reSync(); // show the windows and fill with our information + + ClearUndoManager(); + setModified(false); // and we are not modified yet +} + +OUString OTableController::createUniqueName(const OUString& _rName) +{ + OUString sName = _rName; + Reference< XDatabaseMetaData> xMetaData = getMetaData( ); + + ::comphelper::UStringMixEqual bCase(!xMetaData.is() || xMetaData->supportsMixedCaseQuotedIdentifiers()); + + auto lHasName = [&bCase, &sName](const std::shared_ptr<OTableRow>& rxRow) { + OFieldDescription* pFieldDesc = rxRow->GetActFieldDescr(); + return pFieldDesc && !pFieldDesc->GetName().isEmpty() && bCase(sName, pFieldDesc->GetName()); + }; + + sal_Int32 i = 0; + while(std::any_of(m_vRowList.begin(), m_vRowList.end(), lHasName)) + { + // found a second name of _rName so we need another + sName = _rName + OUString::number(++i); + } + return sName; +} + +OUString OTableController::getPrivateTitle() const +{ + OUString sTitle; + try + { + // get the table + if ( !m_sName.isEmpty() && getConnection().is() ) + { + if ( m_xTable.is() ) + sTitle = ::dbtools::composeTableName( getConnection()->getMetaData(), m_xTable, ::dbtools::EComposeRule::InDataManipulation, false ); + else + sTitle = m_sName; + } + if ( sTitle.isEmpty() ) + { + OUString aName = DBA_RES(STR_TBL_TITLE); + sTitle = o3tl::getToken(aName,0,' ') + OUString::number(getCurrentStartNumber()); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + return sTitle; +} + +void OTableController::reload() +{ + loadData(); // fill the column information from the table + static_cast<OTableDesignView*>(getView())->reSync(); // show the windows and fill with our information + ClearUndoManager(); + setModified(false); // and we are not modified yet + static_cast<OTableDesignView*>(getView())->Invalidate(); +} + +sal_Int32 OTableController::getFirstEmptyRowPosition() +{ + sal_Int32 nRet = 0; + bool bFoundElem = false; + for (auto const& row : m_vRowList) + { + if ( !row || !row->GetActFieldDescr() || row->GetActFieldDescr()->GetName().isEmpty() ) + { + bFoundElem = true; + break; + } + ++nRet; + } + if (!bFoundElem) + { + bool bReadRow = !isAddAllowed(); + auto pTabEdRow = std::make_shared<OTableRow>(); + pTabEdRow->SetReadOnly(bReadRow); + nRet = m_vRowList.size(); + m_vRowList.push_back( pTabEdRow); + } + return nRet; +} + +bool OTableController::isAutoIncrementPrimaryKey() const +{ + return getSdbMetaData().isAutoIncrementPrimaryKey(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/tabledesign/TableDesignControl.cxx b/dbaccess/source/ui/tabledesign/TableDesignControl.cxx new file mode 100644 index 000000000..1526682ed --- /dev/null +++ b/dbaccess/source/ui/tabledesign/TableDesignControl.cxx @@ -0,0 +1,172 @@ +/* -*- 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 <TableDesignControl.hxx> +#include <TableDesignView.hxx> +#include <TableController.hxx> +#include <com/sun/star/util/URL.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <vcl/commandevent.hxx> +#include <vcl/svapp.hxx> +#include <vcl/weldutils.hxx> +#include <helpids.h> + +using namespace ::dbaui; +using namespace ::svt; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::util; +// Defines +#define HANDLE_ID 0 + +OTableRowView::OTableRowView(vcl::Window* pParent) + : EditBrowseBox(pParent, EditBrowseBoxFlags::NONE, WB_TABSTOP|WB_HIDE|WB_3DLOOK, + BrowserMode::COLUMNSELECTION | BrowserMode::MULTISELECTION | + BrowserMode::AUTOSIZE_LASTCOL | BrowserMode::KEEPHIGHLIGHT | + BrowserMode::HLINES | BrowserMode::VLINES) + , m_nDataPos(-1) + , m_nCurrentPos(-1) + , m_nCurUndoActId(0) +{ + SetHelpId(HID_TABDESIGN_BACKGROUND); + SetSizePixel(LogicToPixel(Size(40, 12), MapMode(MapUnit::MapAppFont))); +} + +void OTableRowView::Init() +{ + EditBrowseBox::Init(); + + vcl::Font aFont( GetDataWindow().GetFont() ); + aFont.SetWeight( WEIGHT_NORMAL ); + GetDataWindow().SetFont( aFont ); + + // set font for the headings to light + aFont = GetFont(); + aFont.SetWeight( WEIGHT_LIGHT ); + SetFont(aFont); + + // set up HandleColumn for at maximum 5 digits + InsertHandleColumn(static_cast<sal_uInt16>(GetTextWidth(OUString('0')) * 4)/*, sal_True */); + + BrowserMode const nMode = BrowserMode::COLUMNSELECTION | BrowserMode::MULTISELECTION | BrowserMode::KEEPHIGHLIGHT | + BrowserMode::HLINES | BrowserMode::VLINES | BrowserMode::AUTOSIZE_LASTCOL; + + SetMode(nMode); +} + +void OTableRowView::KeyInput( const KeyEvent& rEvt ) +{ + if (IsDeleteAllowed()) + { + if (rEvt.GetKeyCode().GetCode() == KEY_DELETE && // Delete rows + !rEvt.GetKeyCode().IsShift() && + !rEvt.GetKeyCode().IsMod1()) + { + DeleteRows(); + return; + } + if( rEvt.GetKeyCode().GetCode() == KEY_F2 ) + { + css::util::URL aUrl; + aUrl.Complete = ".uno:DSBEditDoc"; + GetView()->getController().dispatch( aUrl,Sequence< PropertyValue >() ); + } + } + EditBrowseBox::KeyInput(rEvt); +} + +void OTableRowView::Command(const CommandEvent& rEvt) +{ + + switch (rEvt.GetCommand()) + { + case CommandEventId::ContextMenu: + { + if (!rEvt.IsMouseEvent()) + { + EditBrowseBox::Command(rEvt); + return; + } + + sal_uInt16 nColId = GetColumnId(GetColumnAtXPosPixel(rEvt.GetMousePosPixel().X())); + sal_Int32 nRow = GetRowAtYPosPixel(rEvt.GetMousePosPixel().Y()); + + if ( nColId == HANDLE_ID ) + { + ::tools::Rectangle aRect(rEvt.GetMousePosPixel(), Size(1, 1)); + weld::Window* pPopupParent = weld::GetPopupParent(*this, aRect); + std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(pPopupParent, "dbaccess/ui/tabledesignrowmenu.ui")); + std::unique_ptr<weld::Menu> xContextMenu(xBuilder->weld_menu("menu")); + sal_Int32 nSelectRowCount = GetSelectRowCount(); + xContextMenu->set_sensitive("cut", nSelectRowCount != 0); + xContextMenu->set_sensitive("copy", nSelectRowCount != 0); + OString sIdent = xContextMenu->popup_at_rect(pPopupParent, aRect); + if (sIdent == "cut") + cut(); + else if (sIdent == "copy") + copy(); + else if (sIdent == "insert") + { + InsertNewRows( nRow ); + SetNoSelection(); + GoToRow( nRow ); + SeekRow( nRow ); + } + + return; + } + + [[fallthrough]]; + } + default: + EditBrowseBox::Command(rEvt); + } + +} + +void OTableRowView::cut() +{ + CopyRows(); + DeleteRows(); +} + +void OTableRowView::copy() +{ + CopyRows(); +} + +void OTableRowView::paste() +{ + OSL_FAIL("OTableRowView::Paste : (pseudo-) abstract method called !"); +} + +void OTableRowView::Paste( sal_Int32 nRow ) +{ + InsertRows( nRow ); +} + +EditBrowseBox::RowStatus OTableRowView::GetRowStatus(sal_Int32 nRow) const +{ + if (nRow >= 0 && m_nDataPos == nRow) + return CURRENT; + else + return CLEAN; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/tabledesign/TableDesignHelpBar.cxx b/dbaccess/source/ui/tabledesign/TableDesignHelpBar.cxx new file mode 100644 index 000000000..f81123e55 --- /dev/null +++ b/dbaccess/source/ui/tabledesign/TableDesignHelpBar.cxx @@ -0,0 +1,62 @@ +/* -*- 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 <TableDesignHelpBar.hxx> +#include <helpids.h> + +using namespace dbaui; + +#define DETAILS_MIN_HELP_WIDTH 200 + +OTableDesignHelpBar::OTableDesignHelpBar(std::unique_ptr<weld::TextView> xTextWin) + : m_xTextWin(std::move(xTextWin)) +{ + m_xTextWin->set_size_request(DETAILS_MIN_HELP_WIDTH, -1); + m_xTextWin->set_help_id(HID_TAB_DESIGN_HELP_TEXT_FRAME); +} + +void OTableDesignHelpBar::SetHelpText(const OUString& rText) +{ + if (!m_xTextWin) + return; + m_xTextWin->set_text(rText); +} + +bool OTableDesignHelpBar::isCopyAllowed() +{ + int mStartPos, nEndPos; + return m_xTextWin && m_xTextWin->get_selection_bounds(mStartPos, nEndPos); +} + +bool OTableDesignHelpBar::isCutAllowed() { return false; } + +bool OTableDesignHelpBar::isPasteAllowed() { return false; } + +void OTableDesignHelpBar::cut() {} + +void OTableDesignHelpBar::copy() +{ + if (!m_xTextWin) + return; + m_xTextWin->copy_clipboard(); +} + +void OTableDesignHelpBar::paste() {} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/tabledesign/TableDesignView.cxx b/dbaccess/source/ui/tabledesign/TableDesignView.cxx new file mode 100644 index 000000000..f0570ddba --- /dev/null +++ b/dbaccess/source/ui/tabledesign/TableDesignView.cxx @@ -0,0 +1,260 @@ +/* -*- 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 <TableDesignView.hxx> +#include <TableController.hxx> +#include <helpids.h> +#include <FieldDescriptions.hxx> +#include "TEditControl.hxx" +#include "TableFieldDescWin.hxx" +#include <TableRow.hxx> +#include <i18nlangtag/languagetag.hxx> +#include <toolkit/helper/vclunohelper.hxx> +#include <unotools/syslocale.hxx> +#include <memory> + +using namespace ::dbaui; +using namespace ::utl; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::datatransfer::clipboard; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::beans; + +OTableBorderWindow::OTableBorderWindow(OTableDesignView* pParent) + : InterimItemWindow(pParent, "dbaccess/ui/tableborderwindow.ui", "TableBorderWindow", false) + , m_xHorzSplitter(m_xBuilder->weld_paned("splitter")) + , m_xEditorParent(m_xBuilder->weld_container("editor")) + , m_xEditorParentWin(m_xEditorParent->CreateChildFrame()) + , m_xEditorCtrl(VclPtr<OTableEditorCtrl>::Create(VCLUnoHelper::GetWindow(m_xEditorParentWin), pParent)) + , m_xFieldDescParent(m_xBuilder->weld_container("fielddesc")) + , m_xFieldDescWin(new OTableFieldDescWin(m_xFieldDescParent.get(), pParent)) +{ + SetStyle(GetStyle() | WB_DIALOGCONTROL); + + m_xFieldDescWin->SetHelpId(HID_TAB_DESIGN_DESCWIN); + + // set depending windows and controls + m_xEditorCtrl->SetDescrWin(m_xFieldDescWin.get()); +} + +OTableBorderWindow::~OTableBorderWindow() +{ + disposeOnce(); +} + +void OTableBorderWindow::dispose() +{ + // destroy children + m_xEditorCtrl.disposeAndClear(); + m_xEditorParentWin->dispose(); + m_xEditorParentWin.clear(); + m_xEditorParent.reset(); + m_xFieldDescWin.reset(); + m_xFieldDescParent.reset(); + m_xHorzSplitter.reset(); + InterimItemWindow::dispose(); +} + +void OTableBorderWindow::Layout() +{ + // dimensions of parent window + auto nOutputHeight = GetSizePixel().Height(); + auto nOldSplitPos = m_xHorzSplitter->get_position(); + auto nSplitPos = nOldSplitPos; + + // shift range of the splitter is the middle third of the output + auto nDragPosY = nOutputHeight/3; + auto nDragSizeHeight = nOutputHeight/3; + if (nSplitPos < nDragPosY || nSplitPos > nDragPosY + nDragSizeHeight) + nSplitPos = nDragPosY + nDragSizeHeight; + + // set splitter + m_xHorzSplitter->set_position(nSplitPos); + + InterimItemWindow::Layout(); + + if (nOldSplitPos != nSplitPos) + m_xHorzSplitter->set_position(nSplitPos); +} + +void OTableBorderWindow::GetFocus() +{ + InterimItemWindow::GetFocus(); + + // forward the focus to the current cell of the editor control + if (m_xEditorCtrl) + m_xEditorCtrl->GrabFocus(); +} + +OTableDesignView::OTableDesignView( vcl::Window* pParent, + const Reference< XComponentContext >& _rxOrb, + OTableController& _rController + ) : + ODataView( pParent, _rController,_rxOrb ) + ,m_rController( _rController ) + ,m_eChildFocus(NONE) +{ + + try + { + m_aLocale = SvtSysLocale().GetLanguageTag().getLocale(); + } + catch(Exception&) + { + } + + m_pWin = VclPtr<OTableBorderWindow>::Create(this); + + m_pWin->GetDescWin()->connect_focus_in(LINK(this, OTableDesignView, FieldDescFocusIn)); + + m_pWin->Show(); +} + +OTableDesignView::~OTableDesignView() +{ + disposeOnce(); +} + +void OTableDesignView::dispose() +{ + m_pWin->Hide(); + m_pWin.disposeAndClear(); + ODataView::dispose(); +} + +void OTableDesignView::initialize() +{ + GetEditorCtrl()->Init(); + GetDescWin()->Init(); + // first call after the editctrl has been set + + GetEditorCtrl()->Show(); + GetDescWin()->Show(); + + GetEditorCtrl()->DisplayData(0); +} + +void OTableDesignView::resizeDocumentView(tools::Rectangle& _rPlayground) +{ + m_pWin->SetPosSizePixel( _rPlayground.TopLeft(), _rPlayground.GetSize() ); + + // just for completeness: there is no space left, we occupied it all ... + _rPlayground.SetPos( _rPlayground.BottomRight() ); + _rPlayground.SetSize( Size( 0, 0 ) ); +} + +IMPL_LINK_NOARG(OTableDesignView, FieldDescFocusIn, weld::Widget&, void) +{ + m_eChildFocus = DESCRIPTION; +} + +bool OTableDesignView::PreNotify( NotifyEvent& rNEvt ) +{ + if (rNEvt.GetType() == MouseNotifyEvent::GETFOCUS) + { + if( GetDescWin() && GetDescWin()->HasChildPathFocus() ) + m_eChildFocus = DESCRIPTION; + else if ( GetEditorCtrl() && GetEditorCtrl()->HasChildPathFocus() ) + m_eChildFocus = EDITOR; + else + m_eChildFocus = NONE; + } + + return ODataView::PreNotify(rNEvt); +} + +IClipboardTest* OTableDesignView::getActiveChild() const +{ + IClipboardTest* pTest = nullptr; + switch(m_eChildFocus) + { + case DESCRIPTION: + pTest = GetDescWin(); + break; + case EDITOR: + pTest = GetEditorCtrl(); + break; + case NONE: + break; + } + return pTest; +} + +bool OTableDesignView::isCopyAllowed() +{ + IClipboardTest* pTest = getActiveChild(); + return pTest && pTest->isCopyAllowed(); +} + +bool OTableDesignView::isCutAllowed() +{ + IClipboardTest* pTest = getActiveChild(); + return pTest && pTest->isCutAllowed(); +} + +bool OTableDesignView::isPasteAllowed() +{ + IClipboardTest* pTest = getActiveChild(); + return pTest && pTest->isPasteAllowed(); +} + +void OTableDesignView::copy() +{ + IClipboardTest* pTest = getActiveChild(); + if ( pTest ) + pTest->copy(); +} + +void OTableDesignView::cut() +{ + IClipboardTest* pTest = getActiveChild(); + if ( pTest ) + pTest->cut(); +} + +void OTableDesignView::paste() +{ + IClipboardTest* pTest = getActiveChild(); + if ( pTest ) + pTest->paste(); +} + +// set the view readonly or not +void OTableDesignView::setReadOnly(bool _bReadOnly) +{ + GetDescWin()->SetReadOnly(_bReadOnly); + GetEditorCtrl()->SetReadOnly(_bReadOnly); +} + +void OTableDesignView::reSync() +{ + GetEditorCtrl()->DeactivateCell(); + std::shared_ptr<OTableRow> pRow = (*GetEditorCtrl()->GetRowList())[GetEditorCtrl()->GetCurRow()]; + OFieldDescription* pFieldDescr = pRow ? pRow->GetActFieldDescr() : nullptr; + if ( pFieldDescr ) + GetDescWin()->DisplayData(pFieldDescr); +} + +void OTableDesignView::GetFocus() +{ + if ( GetEditorCtrl() ) + GetEditorCtrl()->GrabFocus(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/tabledesign/TableFieldControl.cxx b/dbaccess/source/ui/tabledesign/TableFieldControl.cxx new file mode 100644 index 000000000..aa04b914a --- /dev/null +++ b/dbaccess/source/ui/tabledesign/TableFieldControl.cxx @@ -0,0 +1,154 @@ +/* -*- 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 "TableFieldControl.hxx" +#include <TableController.hxx> +#include <TableDesignView.hxx> +#include "TEditControl.hxx" +#include <strings.hxx> +#include <com/sun/star/sdbc/XDatabaseMetaData.hpp> +#include <comphelper/types.hxx> +#include <TypeInfo.hxx> + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::sdbc; +using namespace dbaui; + +OTableFieldControl::OTableFieldControl(weld::Container* pParent, OTableDesignHelpBar* pHelpBar, OTableDesignView* pView) + : OFieldDescControl(pParent, pHelpBar) + , m_xView(pView) +{ +} + +void OTableFieldControl::dispose() +{ + m_xView.clear(); +} + +OTableFieldControl::~OTableFieldControl() +{ + dispose(); +} + +void OTableFieldControl::CellModified(sal_Int32 nRow, sal_uInt16 nColId ) +{ + GetCtrl()->CellModified(nRow,nColId); +} + +OTableEditorCtrl* OTableFieldControl::GetCtrl() const +{ + assert(m_xView && "no view!"); + return m_xView->GetEditorCtrl(); +} + +bool OTableFieldControl::IsReadOnly() +{ + bool bRead(GetCtrl()->IsReadOnly()); + if( !bRead ) + { + // The columns of a css::sdbcx::View could not be locked + Reference<XPropertySet> xTable = GetCtrl()->GetView()->getController().getTable(); + if(xTable.is() && ::comphelper::getString(xTable->getPropertyValue(PROPERTY_TYPE)) == "VIEW") + bRead = true; + else + { + std::shared_ptr<OTableRow> pCurRow = GetCtrl()->GetActRow(); + if( pCurRow ) + bRead = pCurRow->IsReadOnly(); + } + } + return bRead; +} + +void OTableFieldControl::ActivateAggregate( EControlType eType ) +{ + switch(eType) + { + case tpColumnName: + case tpType: + break; + default: + OFieldDescControl::ActivateAggregate(eType); + } +} + +void OTableFieldControl::DeactivateAggregate( EControlType eType ) +{ + switch(eType) + { + case tpColumnName: + case tpType: + break; + default: + OFieldDescControl::DeactivateAggregate(eType); + } +} + +void OTableFieldControl::SetModified(bool bModified) +{ + GetCtrl()->GetView()->getController().setModified(bModified); +} + +css::uno::Reference< css::sdbc::XConnection> OTableFieldControl::getConnection() +{ + return GetCtrl()->GetView()->getController().getConnection(); +} + +css::uno::Reference< css::sdbc::XDatabaseMetaData> OTableFieldControl::getMetaData() +{ + Reference<XConnection> xCon = GetCtrl()->GetView()->getController().getConnection(); + if(!xCon.is()) + return nullptr; + return xCon->getMetaData(); +} + +Reference< XNumberFormatter > OTableFieldControl::GetFormatter() const +{ + return GetCtrl()->GetView()->getController().getNumberFormatter(); +} + +TOTypeInfoSP OTableFieldControl::getTypeInfo(sal_Int32 _nPos) +{ + return GetCtrl()->GetView()->getController().getTypeInfo(_nPos); +} + +const OTypeInfoMap* OTableFieldControl::getTypeInfo() const +{ + return &GetCtrl()->GetView()->getController().getTypeInfo(); +} + +Locale OTableFieldControl::GetLocale() const +{ + return GetCtrl()->GetView()->getLocale(); +} + +bool OTableFieldControl::isAutoIncrementValueEnabled() const +{ + return GetCtrl()->GetView()->getController().isAutoIncrementValueEnabled(); +} + +OUString OTableFieldControl::getAutoIncrementValue() const +{ + return GetCtrl()->GetView()->getController().getAutoIncrementValue(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/tabledesign/TableFieldControl.hxx b/dbaccess/source/ui/tabledesign/TableFieldControl.hxx new file mode 100644 index 000000000..4a232f86c --- /dev/null +++ b/dbaccess/source/ui/tabledesign/TableFieldControl.hxx @@ -0,0 +1,66 @@ +/* -*- 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 . + */ +#pragma once + +#include <FieldDescControl.hxx> + +namespace dbaui +{ + class OTableEditorCtrl; + class OTableDesignHelpBar; + class OTableDesignView; + + // OTableFieldControl + class OTableFieldControl : public OFieldDescControl + { + VclPtr<OTableDesignView> m_xView; + + OTableEditorCtrl* GetCtrl() const; + + void dispose(); + + protected: + virtual void ActivateAggregate( EControlType eType ) override; + virtual void DeactivateAggregate( EControlType eType ) override; + // are to be implemented by the derived classes + virtual void CellModified(sal_Int32 nRow, sal_uInt16 nColId ) override; + virtual bool IsReadOnly() override; + virtual void SetModified(bool bModified) override; + virtual css::uno::Reference< css::util::XNumberFormatter > GetFormatter() const override; + + virtual css::lang::Locale GetLocale() const override; + + virtual TOTypeInfoSP getTypeInfo(sal_Int32 _nPos) override; + virtual const OTypeInfoMap* getTypeInfo() const override; + virtual bool isAutoIncrementValueEnabled() const override; + virtual OUString getAutoIncrementValue() const override; + + public: + OTableFieldControl(weld::Container* pParent, OTableDesignHelpBar* pHelpBar, OTableDesignView* pView); + virtual ~OTableFieldControl() override; + + using OFieldDescControl::BoolStringPersistent; + using OFieldDescControl::BoolStringUI; + + virtual css::uno::Reference< css::sdbc::XDatabaseMetaData> getMetaData() override; + virtual css::uno::Reference< css::sdbc::XConnection> getConnection() override; + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/tabledesign/TableFieldDescWin.cxx b/dbaccess/source/ui/tabledesign/TableFieldDescWin.cxx new file mode 100644 index 000000000..7e6c4f111 --- /dev/null +++ b/dbaccess/source/ui/tabledesign/TableFieldDescWin.cxx @@ -0,0 +1,140 @@ +/* -*- 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 "TableFieldDescWin.hxx" +#include <FieldDescriptions.hxx> +#include <strings.hrc> +#include <TableDesignHelpBar.hxx> +#include <helpids.h> +#include <core_resource.hxx> + +using namespace dbaui; + +OTableFieldDescWin::OTableFieldDescWin(weld::Container* pParent, OTableDesignView* pView) + : OChildWindow(pParent, "dbaccess/ui/fielddescpanel.ui", "FieldDescPanel") + , m_xHelpBar(new OTableDesignHelpBar(m_xBuilder->weld_text_view("textview"))) + , m_xBox(m_xBuilder->weld_container("box")) + , m_xFieldControl(new OTableFieldControl(m_xBox.get(), m_xHelpBar.get(), pView)) + , m_xHeader(m_xBuilder->weld_label("header")) + , m_eChildFocus(NONE) +{ + // Header + m_xHeader->set_label(DBA_RES(STR_TAB_PROPERTIES)); + + m_xFieldControl->SetHelpId(HID_TAB_DESIGN_FIELDCONTROL); + + m_xHelpBar->connect_focus_in(LINK(this, OTableFieldDescWin, HelpFocusIn)); + m_xFieldControl->connect_focus_in(LINK(this, OTableFieldDescWin, FieldFocusIn)); +} + +bool OTableFieldDescWin::HasChildPathFocus() const +{ + return m_xFieldControl->HasChildPathFocus() || m_xHelpBar->HasFocus(); +} + +OTableFieldDescWin::~OTableFieldDescWin() +{ +} + +void OTableFieldDescWin::Init() +{ + m_xFieldControl->Init(); +} + +void OTableFieldDescWin::SetReadOnly( bool bRead ) +{ + m_xFieldControl->SetReadOnly( bRead ); +} + +void OTableFieldDescWin::DisplayData( OFieldDescription* pFieldDescr ) +{ + m_xFieldControl->DisplayData( pFieldDescr ); +} + +void OTableFieldDescWin::SaveData( OFieldDescription* pFieldDescr ) +{ + m_xFieldControl->SaveData( pFieldDescr ); +} + +IClipboardTest* OTableFieldDescWin::getActiveChild() const +{ + IClipboardTest* pTest = nullptr; + switch(m_eChildFocus) + { + case DESCRIPTION: + pTest = m_xFieldControl.get(); + break; + default: + pTest = m_xHelpBar.get(); + break; + } + return pTest; +} + +bool OTableFieldDescWin::isCopyAllowed() +{ + return getActiveChild() && getActiveChild()->isCopyAllowed(); +} + +bool OTableFieldDescWin::isCutAllowed() +{ + return getActiveChild() && getActiveChild()->isCutAllowed(); +} + +bool OTableFieldDescWin::isPasteAllowed() +{ + return getActiveChild() && getActiveChild()->isPasteAllowed(); +} + +void OTableFieldDescWin::cut() +{ + if (getActiveChild()) + getActiveChild()->cut(); +} + +void OTableFieldDescWin::copy() +{ + if ( getActiveChild() ) + getActiveChild()->copy(); +} + +void OTableFieldDescWin::paste() +{ + if (getActiveChild()) + getActiveChild()->paste(); +} + +void OTableFieldDescWin::GrabFocus() +{ + m_xFieldControl->GrabFocus(); +} + +IMPL_LINK(OTableFieldDescWin, HelpFocusIn, weld::Widget&, rWidget, void) +{ + m_eChildFocus = HELP; + m_aFocusInHdl.Call(rWidget); +} + +IMPL_LINK(OTableFieldDescWin, FieldFocusIn, weld::Widget&, rWidget, void) +{ + m_eChildFocus = DESCRIPTION; + m_aFocusInHdl.Call(rWidget); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/tabledesign/TableFieldDescWin.hxx b/dbaccess/source/ui/tabledesign/TableFieldDescWin.hxx new file mode 100644 index 000000000..9f15c1e1b --- /dev/null +++ b/dbaccess/source/ui/tabledesign/TableFieldDescWin.hxx @@ -0,0 +1,91 @@ +/* -*- 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 . + */ +#pragma once + +#include <IClipBoardTest.hxx> +#include <ChildWindow.hxx> +#include "TableFieldControl.hxx" + +namespace dbaui +{ + class OTableDesignHelpBar; + class OTableDesignView; + class OFieldDescription; + + class OTableFieldDescWin final : public OChildWindow + , public IClipboardTest + { + enum ChildFocusState + { + DESCRIPTION, + HELP, + NONE + }; + private: + std::unique_ptr<OTableDesignHelpBar> m_xHelpBar; + std::unique_ptr<weld::Container> m_xBox; + std::unique_ptr<OTableFieldControl> m_xFieldControl; + std::unique_ptr<weld::Label> m_xHeader; + Link<weld::Widget&, void> m_aFocusInHdl; + + ChildFocusState m_eChildFocus; + + IClipboardTest* getActiveChild() const; + + DECL_LINK(HelpFocusIn, weld::Widget&, void); + DECL_LINK(FieldFocusIn, weld::Widget&, void); + + public: + explicit OTableFieldDescWin(weld::Container* pParent, OTableDesignView* pView); + virtual ~OTableFieldDescWin() override; + + void Init(); + + void DisplayData( OFieldDescription* pFieldDescr ); + void SaveData( OFieldDescription* pFieldDescr ); + void SetReadOnly( bool bReadOnly ); + + void SetControlText( sal_uInt16 nControlId, const OUString& rText ) + { m_xFieldControl->SetControlText(nControlId,rText); } + + OUString BoolStringPersistent(std::u16string_view rUIString) const { return m_xFieldControl->BoolStringPersistent(rUIString); } + OUString BoolStringUI(const OUString& rPersistentString) const { return m_xFieldControl->BoolStringUI(rPersistentString); } + + virtual bool HasChildPathFocus() const override; + virtual void GrabFocus() override; + + // IClipboardTest + virtual bool isCutAllowed() override; + virtual bool isCopyAllowed() override; + virtual bool isPasteAllowed() override; + + virtual void copy() override; + virtual void cut() override; + virtual void paste() override; + + void connect_focus_in(const Link<weld::Widget&, void>& rLink) + { + m_aFocusInHdl = rLink; + } + + OTableFieldControl* getGenPage() const { return m_xFieldControl.get(); } + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/tabledesign/TableRow.cxx b/dbaccess/source/ui/tabledesign/TableRow.cxx new file mode 100644 index 000000000..8f13193e1 --- /dev/null +++ b/dbaccess/source/ui/tabledesign/TableRow.cxx @@ -0,0 +1,183 @@ +/* -*- 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 <TableRow.hxx> +#include <tools/stream.hxx> +#include <FieldDescriptions.hxx> +#include <comphelper/types.hxx> + +using namespace dbaui; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; + +OTableRow::OTableRow() + :m_pActFieldDescr( nullptr ) + ,m_nPos( -1 ) + ,m_bReadOnly( false ) + ,m_bOwnsDescriptions(false) +{ +} + +OTableRow::OTableRow( const OTableRow& rRow, tools::Long nPosition ) + :m_pActFieldDescr(nullptr) + ,m_nPos( nPosition ) + ,m_bReadOnly(rRow.IsReadOnly()) + ,m_bOwnsDescriptions(false) +{ + + OFieldDescription* pSrcField = rRow.GetActFieldDescr(); + if(pSrcField) + { + m_pActFieldDescr = new OFieldDescription(*pSrcField); + m_bOwnsDescriptions = true; + } +} + +OTableRow::~OTableRow() +{ + if(m_bOwnsDescriptions) + delete m_pActFieldDescr; +} + +void OTableRow::SetPrimaryKey( bool bSet ) +{ + if(m_pActFieldDescr) + m_pActFieldDescr->SetPrimaryKey(bSet); +} + +bool OTableRow::IsPrimaryKey() const +{ + return m_pActFieldDescr && m_pActFieldDescr->IsPrimaryKey(); +} + +void OTableRow::SetFieldType( const TOTypeInfoSP& _pType, bool _bForce ) +{ + if ( _pType ) + { + if( !m_pActFieldDescr ) + { + m_pActFieldDescr = new OFieldDescription(); + m_bOwnsDescriptions = true; + } + m_pActFieldDescr->FillFromTypeInfo(_pType,_bForce,true); + } + else + { + delete m_pActFieldDescr; + m_pActFieldDescr = nullptr; + } +} + +namespace dbaui +{ + SvStream& WriteOTableRow( SvStream& _rStr, const OTableRow& _rRow ) + { + _rStr.WriteInt32( _rRow.m_nPos ); + OFieldDescription* pFieldDesc = _rRow.GetActFieldDescr(); + if(pFieldDesc) + { + _rStr.WriteInt32( 1 ); + _rStr.WriteUniOrByteString(pFieldDesc->GetName(), _rStr.GetStreamCharSet()); + _rStr.WriteUniOrByteString(pFieldDesc->GetDescription(), _rStr.GetStreamCharSet()); + _rStr.WriteUniOrByteString(pFieldDesc->GetHelpText(), _rStr.GetStreamCharSet()); + double nValue = 0.0; + Any aValue = pFieldDesc->GetControlDefault(); + if ( aValue >>= nValue ) + { + _rStr.WriteInt32( 1 ); + _rStr.WriteDouble( nValue ); + } + else + { + _rStr.WriteInt32( 2 ); + _rStr.WriteUniOrByteString(::comphelper::getString(aValue), _rStr.GetStreamCharSet()); + } + + _rStr.WriteInt32( pFieldDesc->GetType() ); + + _rStr.WriteInt32( pFieldDesc->GetPrecision() ); + _rStr.WriteInt32( pFieldDesc->GetScale() ); + _rStr.WriteInt32( pFieldDesc->GetIsNullable() ); + _rStr.WriteInt32( pFieldDesc->GetFormatKey() ); + _rStr.WriteInt32( static_cast<sal_Int32>(pFieldDesc->GetHorJustify()) ); + _rStr.WriteInt32( pFieldDesc->IsAutoIncrement() ? 1 : 0 ); + _rStr.WriteInt32( pFieldDesc->IsPrimaryKey() ? 1 : 0 ); + _rStr.WriteInt32( pFieldDesc->IsCurrency() ? 1 : 0 ); + } + else + _rStr.WriteInt32( 0 ); + return _rStr; + } + SvStream& ReadOTableRow( SvStream& _rStr, OTableRow& _rRow ) + { + _rStr.ReadInt32( _rRow.m_nPos ); + sal_Int32 nValue = 0; + _rStr.ReadInt32( nValue ); + if ( !nValue ) + return _rStr; + OFieldDescription* pFieldDesc = new OFieldDescription(); + _rRow.m_pActFieldDescr = pFieldDesc; + pFieldDesc->SetName(_rStr.ReadUniOrByteString(_rStr.GetStreamCharSet())); + pFieldDesc->SetDescription(_rStr.ReadUniOrByteString(_rStr.GetStreamCharSet())); + pFieldDesc->SetHelpText(_rStr.ReadUniOrByteString(_rStr.GetStreamCharSet())); + + _rStr.ReadInt32( nValue ); + Any aControlDefault; + switch ( nValue ) + { + case 1: + { + double nControlDefault; + _rStr.ReadDouble( nControlDefault ); + aControlDefault <<= nControlDefault; + break; + } + case 2: + aControlDefault <<= _rStr.ReadUniOrByteString(_rStr.GetStreamCharSet()); + break; + } + + pFieldDesc->SetControlDefault(aControlDefault); + + _rStr.ReadInt32( nValue ); + pFieldDesc->SetTypeValue(nValue); + + _rStr.ReadInt32( nValue ); + pFieldDesc->SetPrecision(nValue); + _rStr.ReadInt32( nValue ); + pFieldDesc->SetScale(nValue); + _rStr.ReadInt32( nValue ); + pFieldDesc->SetIsNullable(nValue); + _rStr.ReadInt32( nValue ); + pFieldDesc->SetFormatKey(nValue); + _rStr.ReadInt32( nValue ); + pFieldDesc->SetHorJustify(static_cast<SvxCellHorJustify>(nValue)); + + _rStr.ReadInt32( nValue ); + pFieldDesc->SetAutoIncrement(nValue != 0); + _rStr.ReadInt32( nValue ); + pFieldDesc->SetPrimaryKey(nValue != 0); + _rStr.ReadInt32( nValue ); + pFieldDesc->SetCurrency(nValue != 0); + return _rStr; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/tabledesign/TableRowExchange.cxx b/dbaccess/source/ui/tabledesign/TableRowExchange.cxx new file mode 100644 index 000000000..c56450ac1 --- /dev/null +++ b/dbaccess/source/ui/tabledesign/TableRowExchange.cxx @@ -0,0 +1,67 @@ +/* -*- 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 <TableRowExchange.hxx> +#include <sot/formats.hxx> +#include <sot/storage.hxx> +#include <TableRow.hxx> + +namespace dbaui +{ + constexpr sal_uInt32 FORMAT_OBJECT_ID_SBA_TABED = 1; + + using namespace ::com::sun::star::uno; + OTableRowExchange::OTableRowExchange(std::vector< std::shared_ptr<OTableRow> >&& _rvTableRow) + : m_vTableRow(std::move(_rvTableRow)) + { + } + bool OTableRowExchange::WriteObject( tools::SvRef<SotTempStream>& rxOStm, void* pUserObject, sal_uInt32 nUserObjectId, const css::datatransfer::DataFlavor& /*rFlavor*/ ) + { + if(nUserObjectId == FORMAT_OBJECT_ID_SBA_TABED) + { + std::vector< std::shared_ptr<OTableRow> >* pRows = static_cast< std::vector< std::shared_ptr<OTableRow> >* >(pUserObject); + if(pRows) + { + (*rxOStm).WriteInt32( pRows->size() ); // first stream the size + for (auto const& row : *pRows) + WriteOTableRow(*rxOStm, *row); + return true; + } + } + return false; + } + void OTableRowExchange::AddSupportedFormats() + { + if ( !m_vTableRow.empty() ) + AddFormat(SotClipboardFormatId::SBA_TABED); + } + bool OTableRowExchange::GetData( const css::datatransfer::DataFlavor& rFlavor, const OUString& /*rDestDoc*/ ) + { + SotClipboardFormatId nFormat = SotExchange::GetFormat(rFlavor); + if(nFormat == SotClipboardFormatId::SBA_TABED) + return SetObject(&m_vTableRow,FORMAT_OBJECT_ID_SBA_TABED,rFlavor); + return false; + } + void OTableRowExchange::ObjectReleased() + { + m_vTableRow.clear(); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/tabledesign/TableUndo.cxx b/dbaccess/source/ui/tabledesign/TableUndo.cxx new file mode 100644 index 000000000..d60756a2e --- /dev/null +++ b/dbaccess/source/ui/tabledesign/TableUndo.cxx @@ -0,0 +1,352 @@ +/* -*- 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 "TableUndo.hxx" +#include <strings.hrc> +#include "TEditControl.hxx" +#include <TableRow.hxx> +#include <TableController.hxx> +#include <TableDesignView.hxx> +#include <FieldDescriptions.hxx> +#include <svx/svxids.hrc> + +using namespace dbaui; +using namespace ::svt; + + +OTableDesignUndoAct::OTableDesignUndoAct(OTableRowView* pOwner, TranslateId pCommentID) + : OCommentUndoAction(pCommentID) + , m_pTabDgnCtrl(pOwner) +{ + m_pTabDgnCtrl->m_nCurUndoActId++; +} + +OTableDesignUndoAct::~OTableDesignUndoAct() +{ +} + +void OTableDesignUndoAct::Undo() +{ + m_pTabDgnCtrl->m_nCurUndoActId--; + + // doc has not been modified if first undo was reverted + if( m_pTabDgnCtrl->m_nCurUndoActId == 0 ) + { + m_pTabDgnCtrl->GetView()->getController().setModified(false); + m_pTabDgnCtrl->GetView()->getController().InvalidateFeature(SID_SAVEDOC); + } +} + +void OTableDesignUndoAct::Redo() +{ + m_pTabDgnCtrl->m_nCurUndoActId++; + + // restore Modified-flag after Redo of first Undo-action + if( m_pTabDgnCtrl->m_nCurUndoActId > 0 ) + { + m_pTabDgnCtrl->GetView()->getController().setModified(true); + m_pTabDgnCtrl->GetView()->getController().InvalidateFeature(SID_SAVEDOC); + } +} + +OTableDesignCellUndoAct::OTableDesignCellUndoAct( OTableRowView* pOwner, sal_Int32 nRowID, sal_uInt16 nColumn ) : + OTableDesignUndoAct( pOwner ,STR_TABED_UNDO_CELLMODIFIED) + ,m_nCol( nColumn ) + ,m_nRow( nRowID ) +{ + // read text at position (m_nRow, m_nCol) + m_sOldText = m_pTabDgnCtrl->GetCellData( m_nRow, m_nCol ); +} + +OTableDesignCellUndoAct::~OTableDesignCellUndoAct() +{ +} + +void OTableDesignCellUndoAct::Undo() +{ + // store text at old line and restore the old one + m_pTabDgnCtrl->ActivateCell( m_nRow, m_nCol ); + m_sNewText = m_pTabDgnCtrl->GetCellData( m_nRow, m_nCol ); + m_pTabDgnCtrl->SetCellData( m_nRow, m_nCol, m_sOldText ); + // line has not been modified if the first Undo was reverted + if (m_pTabDgnCtrl->GetCurUndoActId() == 1) + { + CellControllerRef xController = m_pTabDgnCtrl->Controller(); + if ( xController.is() ) + xController->SaveValue(); + m_pTabDgnCtrl->GetView()->getController().setModified(false); + + } + + OTableDesignUndoAct::Undo(); +} + +void OTableDesignCellUndoAct::Redo() +{ + // restore new text + m_pTabDgnCtrl->ActivateCell( m_nRow, m_nCol ); + m_pTabDgnCtrl->SetCellData( m_nRow, m_nCol, m_sNewText ); + + OTableDesignUndoAct::Redo(); +} + +OTableEditorUndoAct::OTableEditorUndoAct(OTableEditorCtrl* pOwner, TranslateId pCommentID) + : OTableDesignUndoAct(pOwner, pCommentID) + , pTabEdCtrl(pOwner) +{ +} + +OTableEditorUndoAct::~OTableEditorUndoAct() +{ +} + +OTableEditorTypeSelUndoAct::OTableEditorTypeSelUndoAct( OTableEditorCtrl* pOwner, sal_Int32 nRowID, sal_uInt16 nColumn, const TOTypeInfoSP& _pOldType ) + :OTableEditorUndoAct( pOwner ,STR_TABED_UNDO_TYPE_CHANGED) + ,m_nCol( nColumn ) + ,m_nRow( nRowID ) + ,m_pOldType( _pOldType ) +{ +} + +OTableEditorTypeSelUndoAct::~OTableEditorTypeSelUndoAct() +{ +} + +void OTableEditorTypeSelUndoAct::Undo() +{ + // restore type + OFieldDescription* pFieldDesc = pTabEdCtrl->GetFieldDescr(m_nRow); + if(pFieldDesc) + m_pNewType = pFieldDesc->getTypeInfo(); + else + m_pNewType = TOTypeInfoSP(); + pTabEdCtrl->SetCellData(m_nRow,m_nCol,m_pOldType); + pTabEdCtrl->SwitchType( m_pOldType ); + + OTableEditorUndoAct::Undo(); +} + +void OTableEditorTypeSelUndoAct::Redo() +{ + // new type + pTabEdCtrl->GoToRowColumnId( m_nRow ,m_nCol); + pTabEdCtrl->SetCellData(m_nRow,m_nCol,m_pNewType); + + OTableEditorUndoAct::Redo(); +} + +OTableEditorDelUndoAct::OTableEditorDelUndoAct( OTableEditorCtrl* pOwner) : + OTableEditorUndoAct( pOwner ,STR_TABED_UNDO_ROWDELETED) +{ + // fill DeletedRowList + std::vector< std::shared_ptr<OTableRow> >* pOriginalRows = pOwner->GetRowList(); + sal_Int32 nIndex = pOwner->FirstSelectedRow(); + std::shared_ptr<OTableRow> pOriginalRow; + std::shared_ptr<OTableRow> pNewRow; + + while( nIndex != SFX_ENDOFSELECTION ) + { + pOriginalRow = (*pOriginalRows)[nIndex]; + pNewRow = std::make_shared<OTableRow>( *pOriginalRow, nIndex ); + m_aDeletedRows.push_back( pNewRow); + + nIndex = pOwner->NextSelectedRow(); + } +} + +OTableEditorDelUndoAct::~OTableEditorDelUndoAct() +{ + m_aDeletedRows.clear(); +} + +void OTableEditorDelUndoAct::Undo() +{ + // Insert the deleted line + sal_uLong nPos; + + std::shared_ptr<OTableRow> pNewOrigRow; + std::vector< std::shared_ptr<OTableRow> >* pOriginalRows = pTabEdCtrl->GetRowList(); + + for (auto const& deletedRow : m_aDeletedRows) + { + pNewOrigRow = std::make_shared<OTableRow>( *deletedRow ); + nPos = deletedRow->GetPos(); + pOriginalRows->insert( pOriginalRows->begin()+nPos,pNewOrigRow); + } + + pTabEdCtrl->DisplayData(pTabEdCtrl->GetCurRow()); + pTabEdCtrl->Invalidate(); + OTableEditorUndoAct::Undo(); +} + +void OTableEditorDelUndoAct::Redo() +{ + // delete line again + std::vector< std::shared_ptr<OTableRow> >* pOriginalRows = pTabEdCtrl->GetRowList(); + + for (auto const& deletedRow : m_aDeletedRows) + { + auto it = pOriginalRows->begin() + deletedRow->GetPos(); + pOriginalRows->erase(it); + } + + pTabEdCtrl->DisplayData(pTabEdCtrl->GetCurRow()); + pTabEdCtrl->Invalidate(); + OTableEditorUndoAct::Redo(); +} + +OTableEditorInsUndoAct::OTableEditorInsUndoAct( OTableEditorCtrl* pOwner, + tools::Long nInsertPosition , + std::vector< std::shared_ptr<OTableRow> >&& _vInsertedRows) + :OTableEditorUndoAct( pOwner,STR_TABED_UNDO_ROWINSERTED ) + ,m_vInsertedRows(std::move(_vInsertedRows)) + ,m_nInsPos( nInsertPosition ) +{ +} + +OTableEditorInsUndoAct::~OTableEditorInsUndoAct() +{ + m_vInsertedRows.clear(); +} + +void OTableEditorInsUndoAct::Undo() +{ + // delete lines again + std::vector< std::shared_ptr<OTableRow> >* pOriginalRows = pTabEdCtrl->GetRowList(); + pOriginalRows->erase(pOriginalRows->begin() + m_nInsPos, pOriginalRows->begin() + m_nInsPos + m_vInsertedRows.size()); + + pTabEdCtrl->RowRemoved( m_nInsPos, m_vInsertedRows.size() ); + pTabEdCtrl->InvalidateHandleColumn(); + + OTableEditorUndoAct::Undo(); +} + +void OTableEditorInsUndoAct::Redo() +{ + // insert lines again + sal_Int32 nInsertRow = m_nInsPos; + std::shared_ptr<OTableRow> pRow; + std::vector< std::shared_ptr<OTableRow> >* pRowList = pTabEdCtrl->GetRowList(); + for (auto const& insertedRow : m_vInsertedRows) + { + pRow = std::make_shared<OTableRow>( *insertedRow ); + pRowList->insert( pRowList->begin()+nInsertRow ,pRow ); + nInsertRow++; + } + + pTabEdCtrl->RowInserted( m_nInsPos, m_vInsertedRows.size() ); + pTabEdCtrl->InvalidateHandleColumn(); + + OTableEditorUndoAct::Redo(); +} + +OTableEditorInsNewUndoAct::OTableEditorInsNewUndoAct( OTableEditorCtrl* pOwner, sal_Int32 nInsertPosition, sal_Int32 nInsertedRows ) : + OTableEditorUndoAct( pOwner ,STR_TABED_UNDO_NEWROWINSERTED) + ,m_nInsPos( nInsertPosition ) + ,m_nInsRows( nInsertedRows ) +{ +} + +OTableEditorInsNewUndoAct::~OTableEditorInsNewUndoAct() +{ +} + +void OTableEditorInsNewUndoAct::Undo() +{ + // delete inserted lines + std::vector< std::shared_ptr<OTableRow> >* pOriginalRows = pTabEdCtrl->GetRowList(); + + pOriginalRows->erase(pOriginalRows->begin() + m_nInsPos, pOriginalRows->begin() + m_nInsPos + m_nInsRows); + + pTabEdCtrl->RowRemoved( m_nInsPos, m_nInsRows ); + pTabEdCtrl->InvalidateHandleColumn(); + + OTableEditorUndoAct::Undo(); +} + +void OTableEditorInsNewUndoAct::Redo() +{ + // insert lines again + std::vector< std::shared_ptr<OTableRow> >* pRowList = pTabEdCtrl->GetRowList(); + + for( tools::Long i=m_nInsPos; i<(m_nInsPos+m_nInsRows); i++ ) + pRowList->insert( pRowList->begin()+i,std::make_shared<OTableRow>() ); + + pTabEdCtrl->RowInserted( m_nInsPos, m_nInsRows ); + pTabEdCtrl->InvalidateHandleColumn(); + + OTableEditorUndoAct::Redo(); +} + +OPrimKeyUndoAct::OPrimKeyUndoAct( OTableEditorCtrl* pOwner, const MultiSelection& aDeletedKeys, const MultiSelection& aInsertedKeys) : + OTableEditorUndoAct( pOwner ,STR_TABLEDESIGN_UNDO_PRIMKEY) + ,m_aDelKeys( aDeletedKeys ) + ,m_aInsKeys( aInsertedKeys ) + ,m_pEditorCtrl( pOwner ) +{ +} + +OPrimKeyUndoAct::~OPrimKeyUndoAct() +{ +} + +void OPrimKeyUndoAct::Undo() +{ + std::vector< std::shared_ptr<OTableRow> >* pRowList = pTabEdCtrl->GetRowList(); + std::shared_ptr<OTableRow> pRow; + tools::Long nIndex; + + // delete inserted keys + for( nIndex = m_aInsKeys.FirstSelected(); nIndex != tools::Long(SFX_ENDOFSELECTION); nIndex=m_aInsKeys.NextSelected() ) + { + OSL_ENSURE(nIndex <= static_cast<tools::Long>(pRowList->size()),"Index for undo isn't valid!"); + pRow = (*pRowList)[nIndex]; + pRow->SetPrimaryKey( false ); + } + + // restore deleted keys + for( nIndex = m_aDelKeys.FirstSelected(); nIndex != tools::Long(SFX_ENDOFSELECTION); nIndex=m_aDelKeys.NextSelected() ) + { + OSL_ENSURE(nIndex <= static_cast<tools::Long>(pRowList->size()),"Index for undo isn't valid!"); + pRow = (*pRowList)[nIndex]; + pRow->SetPrimaryKey( true ); + } + + m_pEditorCtrl->InvalidateHandleColumn(); + OTableEditorUndoAct::Undo(); +} + +void OPrimKeyUndoAct::Redo() +{ + std::vector< std::shared_ptr<OTableRow> >* pRowList = pTabEdCtrl->GetRowList(); + tools::Long nIndex; + + // delete the deleted keys + for( nIndex = m_aDelKeys.FirstSelected(); nIndex != tools::Long(SFX_ENDOFSELECTION); nIndex=m_aDelKeys.NextSelected() ) + (*pRowList)[nIndex]->SetPrimaryKey( false ); + + // restore the inserted keys + for( nIndex = m_aInsKeys.FirstSelected(); nIndex != tools::Long(SFX_ENDOFSELECTION); nIndex=m_aInsKeys.NextSelected() ) + (*pRowList)[nIndex]->SetPrimaryKey( true ); + + m_pEditorCtrl->InvalidateHandleColumn(); + OTableEditorUndoAct::Redo(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/tabledesign/TableUndo.hxx b/dbaccess/source/ui/tabledesign/TableUndo.hxx new file mode 100644 index 000000000..5ad23b84f --- /dev/null +++ b/dbaccess/source/ui/tabledesign/TableUndo.hxx @@ -0,0 +1,136 @@ +/* -*- 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 . + */ +#pragma once + +#include <GeneralUndo.hxx> +#include <tools/multisel.hxx> + +#include <vector> + +#include <com/sun/star/uno/Any.h> +#include <TypeInfo.hxx> +#include <vcl/vclptr.hxx> + +namespace dbaui +{ + class OTableRowView; + class OTableRow; + class OTableDesignUndoAct : public OCommentUndoAction + { + protected: + VclPtr<OTableRowView> m_pTabDgnCtrl; + + virtual void Undo() override; + virtual void Redo() override; + public: + OTableDesignUndoAct(OTableRowView* pOwner, TranslateId pCommentID); + virtual ~OTableDesignUndoAct() override; + }; + + class OTableEditorCtrl; + class OTableEditorUndoAct : public OTableDesignUndoAct + { + protected: + VclPtr<OTableEditorCtrl> pTabEdCtrl; + + public: + OTableEditorUndoAct(OTableEditorCtrl* pOwner, TranslateId pCommentID); + virtual ~OTableEditorUndoAct() override; + }; + + class OTableDesignCellUndoAct final : public OTableDesignUndoAct + { + sal_uInt16 m_nCol; + sal_Int32 m_nRow; + css::uno::Any m_sOldText; + css::uno::Any m_sNewText; + + virtual void Undo() override; + virtual void Redo() override; + public: + OTableDesignCellUndoAct( OTableRowView* pOwner, sal_Int32 nRowID, sal_uInt16 nColumn ); + virtual ~OTableDesignCellUndoAct() override; + }; + + class OTableEditorTypeSelUndoAct final : public OTableEditorUndoAct + { + sal_uInt16 m_nCol; + sal_Int32 m_nRow; + TOTypeInfoSP m_pOldType; + TOTypeInfoSP m_pNewType; + + virtual void Undo() override; + virtual void Redo() override; + public: + OTableEditorTypeSelUndoAct( OTableEditorCtrl* pOwner, sal_Int32 nRowID, sal_uInt16 nColumn, const TOTypeInfoSP& _pOldType ); + virtual ~OTableEditorTypeSelUndoAct() override; + }; + + class OTableEditorDelUndoAct final : public OTableEditorUndoAct + { + std::vector< std::shared_ptr<OTableRow> > m_aDeletedRows; + + virtual void Undo() override; + virtual void Redo() override; + public: + explicit OTableEditorDelUndoAct( OTableEditorCtrl* pOwner ); + virtual ~OTableEditorDelUndoAct() override; + }; + + class OTableEditorInsUndoAct final : public OTableEditorUndoAct + { + std::vector< std::shared_ptr<OTableRow> > m_vInsertedRows; + tools::Long m_nInsPos; + + virtual void Undo() override; + virtual void Redo() override; + public: + OTableEditorInsUndoAct( OTableEditorCtrl* pOwner, + tools::Long nInsertPosition, + std::vector< std::shared_ptr<OTableRow> >&& _vInsertedRows); + virtual ~OTableEditorInsUndoAct() override; + }; + + class OTableEditorInsNewUndoAct final : public OTableEditorUndoAct + { + sal_Int32 m_nInsPos; + sal_Int32 m_nInsRows; + + virtual void Undo() override; + virtual void Redo() override; + public: + OTableEditorInsNewUndoAct( OTableEditorCtrl* pOwner, sal_Int32 nInsertPosition, sal_Int32 nInsertedRows ); + virtual ~OTableEditorInsNewUndoAct() override; + }; + + class OPrimKeyUndoAct final : public OTableEditorUndoAct + { + MultiSelection m_aDelKeys, + m_aInsKeys; + VclPtr<OTableEditorCtrl> m_pEditorCtrl; + + virtual void Undo() override; + virtual void Redo() override; + public: + OPrimKeyUndoAct( OTableEditorCtrl* pOwner, const MultiSelection& aDeletedKeys, const MultiSelection& aInsertedKeys ); + virtual ~OPrimKeyUndoAct() override; + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |