From 940b4d1848e8c70ab7642901a68594e8016caffc Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 27 Apr 2024 18:51:28 +0200 Subject: Adding upstream version 1:7.0.4. Signed-off-by: Daniel Baumann --- dbaccess/source/ui/tabledesign/FieldDescGenWin.cxx | 149 ++ dbaccess/source/ui/tabledesign/FieldDescGenWin.hxx | 74 + .../source/ui/tabledesign/FieldDescriptions.cxx | 641 ++++++++ dbaccess/source/ui/tabledesign/TEditControl.cxx | 1633 ++++++++++++++++++++ dbaccess/source/ui/tabledesign/TEditControl.hxx | 205 +++ dbaccess/source/ui/tabledesign/TableController.cxx | 1511 ++++++++++++++++++ .../source/ui/tabledesign/TableDesignControl.cxx | 181 +++ .../source/ui/tabledesign/TableDesignHelpBar.cxx | 105 ++ dbaccess/source/ui/tabledesign/TableDesignView.cxx | 302 ++++ .../source/ui/tabledesign/TableFieldControl.cxx | 144 ++ .../source/ui/tabledesign/TableFieldControl.hxx | 60 + .../source/ui/tabledesign/TableFieldDescWin.cxx | 275 ++++ .../source/ui/tabledesign/TableFieldDescWin.hxx | 95 ++ dbaccess/source/ui/tabledesign/TableRow.cxx | 193 +++ .../source/ui/tabledesign/TableRowExchange.cxx | 68 + dbaccess/source/ui/tabledesign/TableUndo.cxx | 352 +++++ dbaccess/source/ui/tabledesign/TableUndo.hxx | 138 ++ 17 files changed, 6126 insertions(+) create mode 100644 dbaccess/source/ui/tabledesign/FieldDescGenWin.cxx create mode 100644 dbaccess/source/ui/tabledesign/FieldDescGenWin.hxx create mode 100644 dbaccess/source/ui/tabledesign/FieldDescriptions.cxx create mode 100644 dbaccess/source/ui/tabledesign/TEditControl.cxx create mode 100644 dbaccess/source/ui/tabledesign/TEditControl.hxx create mode 100644 dbaccess/source/ui/tabledesign/TableController.cxx create mode 100644 dbaccess/source/ui/tabledesign/TableDesignControl.cxx create mode 100644 dbaccess/source/ui/tabledesign/TableDesignHelpBar.cxx create mode 100644 dbaccess/source/ui/tabledesign/TableDesignView.cxx create mode 100644 dbaccess/source/ui/tabledesign/TableFieldControl.cxx create mode 100644 dbaccess/source/ui/tabledesign/TableFieldControl.hxx create mode 100644 dbaccess/source/ui/tabledesign/TableFieldDescWin.cxx create mode 100644 dbaccess/source/ui/tabledesign/TableFieldDescWin.hxx create mode 100644 dbaccess/source/ui/tabledesign/TableRow.cxx create mode 100644 dbaccess/source/ui/tabledesign/TableRowExchange.cxx create mode 100644 dbaccess/source/ui/tabledesign/TableUndo.cxx create mode 100644 dbaccess/source/ui/tabledesign/TableUndo.hxx (limited to 'dbaccess/source/ui/tabledesign') diff --git a/dbaccess/source/ui/tabledesign/FieldDescGenWin.cxx b/dbaccess/source/ui/tabledesign/FieldDescGenWin.cxx new file mode 100644 index 000000000..1a052c190 --- /dev/null +++ b/dbaccess/source/ui/tabledesign/FieldDescGenWin.cxx @@ -0,0 +1,149 @@ +/* -*- 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 "FieldDescGenWin.hxx" +#include +#include +#include +#include "TableFieldControl.hxx" +#include +#include "TEditControl.hxx" + +using namespace dbaui; + +OFieldDescGenWin::OFieldDescGenWin( vcl::Window* pParent, OTableDesignHelpBar* pHelp ) : + TabPage( pParent, WB_3DLOOK | WB_DIALOGCONTROL ) +{ + m_pFieldControl = VclPtr::Create(this,pHelp); + m_pFieldControl->SetHelpId(HID_TAB_DESIGN_FIELDCONTROL); + m_pFieldControl->Show(); +} + +OFieldDescGenWin::~OFieldDescGenWin() +{ + disposeOnce(); +} + +void OFieldDescGenWin::dispose() +{ + m_pFieldControl.disposeAndClear(); + TabPage::dispose(); +} + +void OFieldDescGenWin::Init() +{ + OSL_ENSURE(GetEditorCtrl() != nullptr, "OFieldDescGenWin::Init : have no editor control !"); + + m_pFieldControl->Init(); +} + +void OFieldDescGenWin::Resize() +{ + m_pFieldControl->SetPosSizePixel(Point(0,0),GetSizePixel()); + m_pFieldControl->Resize(); +} + +void OFieldDescGenWin::SetReadOnly( bool bReadOnly ) +{ + + m_pFieldControl->SetReadOnly(bReadOnly); +} + +void OFieldDescGenWin::SetControlText( sal_uInt16 nControlId, const OUString& rText ) +{ + // set texts of the controls + m_pFieldControl->SetControlText(nControlId,rText); +} + +void OFieldDescGenWin::DisplayData( OFieldDescription* pFieldDescr ) +{ + m_pFieldControl->DisplayData(pFieldDescr); +} + +OTableEditorCtrl* OFieldDescGenWin::GetEditorCtrl() +{ + OTableDesignView* pDesignWin = static_cast(GetParent()->GetParent()->GetParent()); + return pDesignWin->GetEditorCtrl(); +} + +void OFieldDescGenWin::SaveData( OFieldDescription* pFieldDescr ) +{ + m_pFieldControl->SaveData(pFieldDescr); +} + +void OFieldDescGenWin::GetFocus() +{ + // sets the focus to the control that was active last + TabPage::GetFocus(); + if(m_pFieldControl) + m_pFieldControl->GetFocus(); + +} + +void OFieldDescGenWin::LoseFocus() +{ + if (m_pFieldControl) + m_pFieldControl->LoseFocus(); + TabPage::LoseFocus(); +} + +OUString OFieldDescGenWin::BoolStringPersistent(const OUString& rUIString) const +{ + return m_pFieldControl->BoolStringPersistent(rUIString); +} + +OUString OFieldDescGenWin::BoolStringUI(const OUString& rPersistentString) const +{ + return m_pFieldControl->BoolStringUI(rPersistentString); +} + +bool OFieldDescGenWin::isCopyAllowed() +{ + return (m_pFieldControl && m_pFieldControl->isCutAllowed()); +} + +bool OFieldDescGenWin::isCutAllowed() +{ + return (m_pFieldControl && m_pFieldControl->isCutAllowed()); +} + +bool OFieldDescGenWin::isPasteAllowed() +{ + return (m_pFieldControl && m_pFieldControl->isPasteAllowed()); +} + +void OFieldDescGenWin::cut() +{ + if(m_pFieldControl) + m_pFieldControl->cut(); +} + +void OFieldDescGenWin::copy() +{ + if(m_pFieldControl) + m_pFieldControl->copy(); +} + +void OFieldDescGenWin::paste() +{ + if(m_pFieldControl) + m_pFieldControl->paste(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/tabledesign/FieldDescGenWin.hxx b/dbaccess/source/ui/tabledesign/FieldDescGenWin.hxx new file mode 100644 index 000000000..b43f8d1fa --- /dev/null +++ b/dbaccess/source/ui/tabledesign/FieldDescGenWin.hxx @@ -0,0 +1,74 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_TABLEDESIGN_FIELDDESCGENWIN_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_TABLEDESIGN_FIELDDESCGENWIN_HXX + +#include +#include + +namespace dbaui +{ + class OTableDesignHelpBar; + class OFieldDescription; + class OTableFieldControl; + class OTableEditorCtrl; + class OFieldDescGenWin : public TabPage + ,public IClipboardTest + { + + VclPtr m_pFieldControl; + protected: + virtual void Resize() override; + + public: + OFieldDescGenWin( vcl::Window* pParent, OTableDesignHelpBar* pHelpBar ); + virtual ~OFieldDescGenWin() override; + virtual void dispose() override; + + virtual void GetFocus() override; + virtual void LoseFocus() override; + void Init(); + + void DisplayData( OFieldDescription* pFieldDescr ); + void SaveData( OFieldDescription* pFieldDescr ); + void SetControlText( sal_uInt16 nControlId, const OUString& rText ); + void SetReadOnly( bool bReadOnly ); + OTableEditorCtrl* GetEditorCtrl(); + + // short GetFormatCategory(OFieldDescription* pFieldDescr); + // gives you one of the CAT_xxx-values (CAT_NUMBER, CAT_DATE ...) belonging to the format specified by the field + + OUString BoolStringPersistent(const OUString& rUIString) const; + OUString BoolStringUI(const OUString& rPersistentString) const; + + // 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; + + OTableFieldControl* getFieldControl() const { return m_pFieldControl; } + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_UI_TABLEDESIGN_FIELDDESCGENWIN_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/tabledesign/FieldDescriptions.cxx b/dbaccess/source/ui/tabledesign/FieldDescriptions.cxx new file mode 100644 index 000000000..6882f1216 --- /dev/null +++ b/dbaccess/source/ui/tabledesign/FieldDescriptions.cxx @@ -0,0 +1,641 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include +#include + +#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_pType() + ,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_pType() + ,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 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.get() == nullptr || 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(nPrec,_pType->nPrecision)); + } + break; + case DataType::TIMESTAMP: + if ( bForce && _pType->nMaximumScale) + { + SetScale(std::min(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(nPrec ? nPrec : DEFAULT_NUMERIC_PRECISION,_pType->nPrecision)); + if ( _pType->nMaximumScale ) + SetScale(std::min(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,makeAny(_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,makeAny(_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,makeAny(_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,makeAny(_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,makeAny(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,makeAny(_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,makeAny(_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,makeAny(_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,makeAny(_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,makeAny(_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,makeAny( dbaui::mapTextAllign(_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,makeAny(_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(); + *pSpecialType = *m_pType; + pSpecialType->nPrecision = GetPrecision(); + pSpecialType->nMaximumScale = static_cast(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,makeAny(_sTypeName)); + else + m_sTypeName = _sTypeName; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +void OFieldDescription::copyColumnSettingsTo(const Reference< XPropertySet >& _rxColumn) +{ + if ( !_rxColumn.is() ) + return; + + Reference xInfo = _rxColumn->getPropertySetInfo(); + + if ( GetFormatKey() != NumberFormat::ALL && xInfo->hasPropertyByName(PROPERTY_FORMATKEY) ) + _rxColumn->setPropertyValue(PROPERTY_FORMATKEY,makeAny(GetFormatKey())); + if ( GetHorJustify() != SvxCellHorJustify::Standard && xInfo->hasPropertyByName(PROPERTY_ALIGN) ) + _rxColumn->setPropertyValue(PROPERTY_ALIGN,makeAny(dbaui::mapTextAllign(GetHorJustify()))); + if ( !GetHelpText().isEmpty() && xInfo->hasPropertyByName(PROPERTY_HELPTEXT) ) + _rxColumn->setPropertyValue(PROPERTY_HELPTEXT,makeAny(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,makeAny(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..6f5128faa --- /dev/null +++ b/dbaccess/source/ui/tabledesign/TEditControl.cxx @@ -0,0 +1,1633 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "TableUndo.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include "TableFieldControl.hxx" +#include +#include +#include + +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_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) + :OTableRowView(pWindow) + ,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 + long 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 = EDIT_NOLIMIT; + OUString sExtraNameChars; + Reference xCon; + try + { + xCon = GetView()->getController().getConnection(); + Reference< XDatabaseMetaData> xMetaData = xCon.is() ? xCon->getMetaData() : Reference< XDatabaseMetaData>(); + + nMaxTextLen = xMetaData.is() ? xMetaData->getMaxColumnNameLength() : 0; + + if( nMaxTextLen == 0 ) + nMaxTextLen = EDIT_NOLIMIT; + sExtraNameChars = xMetaData.is() ? xMetaData->getExtraNameCharacters() : OUString(); + + } + catch(SQLException&) + { + OSL_FAIL("getMaxColumnNameLength"); + } + + pNameCell = VclPtr::Create(&GetDataWindow(), WB_LEFT, sExtraNameChars); + pNameCell->SetMaxTextLen( nMaxTextLen ); + pNameCell->setCheck( isSQL92CheckEnabled(xCon) ); + + // Cell type + pTypeCell = VclPtr::Create( &GetDataWindow() ); + + // Cell description + pDescrCell = VclPtr::Create( &GetDataWindow(), WB_LEFT ); + pDescrCell->SetMaxTextLen( MAX_DESCR_LEN ); + + pHelpTextCell = VclPtr::Create( &GetDataWindow(), WB_LEFT ); + pHelpTextCell->SetMaxTextLen( 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->ClearModifyFlag(); + pDescrCell->ClearModifyFlag(); + pHelpTextCell->ClearModifyFlag(); + 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.clear(); + OTableRowView::dispose(); +} + +bool OTableEditorCtrl::SetDataPtr( long nRow ) +{ + if(nRow == -1) + return false; + + OSL_ENSURE(nRow < static_cast(m_pRowList->size()),"Row is greater than size!"); + if(nRow >= static_cast(m_pRowList->size())) + return false; + pActRow = (*m_pRowList)[nRow]; + return pActRow != nullptr; +} + +bool OTableEditorCtrl::SeekRow(long _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( PushFlags::CLIPREGION ); + rDev.SetClipRegion(vcl::Region(rRect)); + rDev.DrawText( rRect, aText, DrawTextFlags::Left | DrawTextFlags::VCenter ); + rDev.Pop(); +} + +CellController* OTableEditorCtrl::GetController(long nRow, sal_uInt16 nColumnId) +{ + // If EditorCtrl is ReadOnly, editing is forbidden + Reference 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&, long 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(); + pNameCell->SetText( aInitString ); + pNameCell->SaveValue(); + 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(); + pHelpTextCell->SetText( aInitString ); + pHelpTextCell->SaveValue(); + break; + case COLUMN_DESCRIPTION: + if( pActFieldDescr ) + aInitString = pActFieldDescr->GetDescription(); + pDescrCell->SetText( aInitString ); + pDescrCell->SaveValue(); + break; + + } +} + +EditBrowseBox::RowStatus OTableEditorCtrl::GetRowStatus(long nRow) const +{ + const_cast(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(long 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( const OUString& rFieldName ) +{ + + Reference 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(long 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 + const OUString aName(pNameCell->GetText()); + + if( aName.isEmpty() ) + { + // If FieldDescr exists, the field is deleted and the old content restored + if (pActFieldDescr) + { + GetUndoManager().AddUndoAction(std::make_unique(this, nRow, FIELD_TYPE, pActFieldDescr->getTypeInfo())); + SwitchType(TOTypeInfoSP()); + pActFieldDescr = pActRow->GetActFieldDescr(); + } + else + return; + } + if(pActFieldDescr) + pActFieldDescr->SetName( aName ); + pNameCell->ClearModifyFlag(); + + break; + } + + // Store the field type + case FIELD_TYPE: + break; + + // Store DescrCell + case HELP_TEXT: + { + // if the current field description is NULL, set Default + if( !pActFieldDescr ) + { + pHelpTextCell->SetText(OUString()); + pHelpTextCell->ClearModifyFlag(); + } + else + pActFieldDescr->SetHelpText( pHelpTextCell->GetText() ); + break; + } + case COLUMN_DESCRIPTION: + { + // Set the default if the field description is null + if( !pActFieldDescr ) + { + pDescrCell->SetText(OUString()); + pDescrCell->ClearModifyFlag(); + } + else + pActFieldDescr->SetDescription( pDescrCell->GetText() ); + 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(long 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( long 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(this, nRow, nColId+1, TOTypeInfoSP()) ); + } + + if( nColId != FIELD_TYPE ) + GetUndoManager().AddUndoAction( std::make_unique(this, nRow, nColId) ); + else + { + GetUndoManager().AddUndoAction(std::make_unique(this, GetCurRow(), nColId, GetFieldDescr(GetCurRow())->getTypeInfo())); + resetType(); + } + + SaveData(nRow,nColId); + // SaveData could create an undo action as well + GetUndoManager().LeaveListAction(); + RowModified(nRow); + CellControllerRef xController(Controller()); + if(xController.is()) + xController->SetModified(); + + // 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 pClipboardRow; + std::shared_ptr pRow; + std::vector< std::shared_ptr > vClipboardList; + vClipboardList.reserve(GetSelectRowCount()); + + for( 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( *pRow ); + vClipboardList.push_back( pClipboardRow); + } + } + if(!vClipboardList.empty()) + { + rtl::Reference pData = new OTableRowExchange(vClipboardList); + pData->CopyToClipboard(GetParent()); + } +} + +OUString OTableEditorCtrl::GenerateName( const OUString& rName ) +{ + // Create a base name for appending numbers to + OUString aBaseName; + Reference 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( long nRow ) +{ + + std::vector< std::shared_ptr > vInsertedUndoRedoRows; // need for undo/redo handling + // get rows from clipboard + TransferableDataHelper aTransferData(TransferableDataHelper::CreateFromSystemClipboard(GetParent())); + if(aTransferData.HasFormat(SotClipboardFormatId::SBA_TABED)) + { + ::tools::SvRef aStreamRef; + bool bOk = aTransferData.GetSotStorageStream(SotClipboardFormatId::SBA_TABED,aStreamRef); + if (bOk && aStreamRef.is()) + { + aStreamRef->Seek(STREAM_SEEK_TO_BEGIN); + aStreamRef->ResetError(); + long nInsertRow = nRow; + std::shared_ptr pRow; + sal_Int32 nSize = 0; + (*aStreamRef).ReadInt32( nSize ); + vInsertedUndoRedoRows.reserve(nSize); + for(sal_Int32 i=0;i < nSize;++i) + { + pRow = std::make_shared(); + 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(*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(this, nRow,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(this) ); + + // Delete all marked rows + 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()); + 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( long nRow ) +{ + OSL_ENSURE(GetView()->getController().isAddAllowed(),"Call of InsertNewRows not valid here. Please check isAppendAllowed!"); + // Create Undo-Action + long nInsertRows = GetSelectRowCount(); + if( !nInsertRows ) + nInsertRows = 1; + GetUndoManager().AddUndoAction( std::make_unique(this, nRow, nInsertRows) ); + // Insert the number of selected rows + for( long i=nRow; i<(nRow+nInsertRows); i++ ) + m_pRowList->insert( m_pRowList->begin()+i ,std::make_shared()); + RowInserted( nRow, nInsertRows ); + + GetView()->getController().setModified( true ); + InvalidateFeatures(); +} + +void OTableEditorCtrl::SetControlText( long 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( long 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( long 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()->getFieldControl()->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(makeAny(sValue)); + break; + + case FIELD_PROPERTY_FORMAT: + { + sValue = ::comphelper::getString(_rNewData); + pFieldDescr->SetFormatKey(sValue.toInt32()); + } + break; + } + + SetControlText(nRow,nColId,sValue); +} + +Any OTableEditorCtrl::GetCellData( long 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 makeAny(sValue); +} + +OUString OTableEditorCtrl::GetCellText( long nRow, sal_uInt16 nColId ) const +{ + OUString sCellText; + const_cast< OTableEditorCtrl* >( this )->GetCellData( nRow, nColId ) >>= sCellText; + return sCellText; +} + +sal_uInt32 OTableEditorCtrl::GetTotalCellWidth(long nRow, sal_uInt16 nColId) +{ + return GetTextWidth(GetCellText(nRow, nColId)) + 2 * GetTextWidth("0"); +} + +OFieldDescription* OTableEditorCtrl::GetFieldDescr( long nRow ) +{ + std::vector< std::shared_ptr >::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 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) + { + switch(m_eChildFocus) + { + case DESCRIPTION: + bIsCutAllowed = !pDescrCell->GetSelected().isEmpty(); + break; + case HELPTEXT: + bIsCutAllowed = !pHelpTextCell->GetSelected().isEmpty(); + break; + case NAME: + bIsCutAllowed = !pNameCell->GetSelected().isEmpty(); + break; + case ROW: + bIsCutAllowed = IsCopyAllowed(); + break; + default: + bIsCutAllowed = false; + break; + } + } + + return bIsCutAllowed; +} + +bool OTableEditorCtrl::IsCopyAllowed() +{ + bool bIsCopyAllowed = false; + if(m_eChildFocus == DESCRIPTION ) + bIsCopyAllowed = !pDescrCell->GetSelected().isEmpty(); + else if(HELPTEXT == m_eChildFocus ) + bIsCopyAllowed = !pHelpTextCell->GetSelected().isEmpty(); + else if(m_eChildFocus == NAME) + bIsCopyAllowed = !pNameCell->GetSelected().isEmpty(); + else if(m_eChildFocus == ROW) + { + Reference 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 pRow; + 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->Cut(); + CellModified(-1,FIELD_NAME); + } + } + else if(m_eChildFocus == DESCRIPTION) + { + if(GetView()->getController().isAlterAllowed()) + { + SaveData(-1,COLUMN_DESCRIPTION); + pDescrCell->Cut(); + CellModified(-1,COLUMN_DESCRIPTION); + } + } + else if(HELPTEXT == m_eChildFocus ) + { + if(GetView()->getController().isAlterAllowed()) + { + SaveData(-1,HELP_TEXT); + pHelpTextCell->Cut(); + 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) + pNameCell->Copy(); + else if(HELPTEXT == m_eChildFocus ) + pHelpTextCell->Copy(); + else if(m_eChildFocus == DESCRIPTION ) + pDescrCell->Copy(); +} + +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->Paste(); + CellModified(); + } + } + else if(HELPTEXT == m_eChildFocus ) + { + if(GetView()->getController().isAlterAllowed()) + { + pHelpTextCell->Paste(); + CellModified(); + } + } + else if(m_eChildFocus == DESCRIPTION) + { + if(GetView()->getController().isAlterAllowed()) + { + pDescrCell->Paste(); + CellModified(); + } + } +} + +bool OTableEditorCtrl::IsDeleteAllowed() +{ + + return GetSelectRowCount() != 0 && GetView()->getController().isDropAllowed(); +} + +bool OTableEditorCtrl::IsInsertNewAllowed( long 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 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). + long nIndex = FirstSelectedRow(); + std::shared_ptr 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())); + long 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 ); + + VclBuilder aBuilder(nullptr, VclBuilderContainer::getUIRootDir(), "dbaccess/ui/querycolmenu.ui", ""); + VclPtr aContextMenu(aBuilder.get_menu("menu")); + aContextMenu->EnableItem(aContextMenu->GetItemId("delete"), false); + aContextMenu->RemoveDisabledEntries(true, true); + if (aContextMenu->Execute(this, aMenuPos) == aContextMenu->GetItemId("width")) + adjustBrowseBoxColumnWidth( this, nColId ); + } + } + } + else + { + VclBuilder aBuilder(nullptr, VclBuilderContainer::getUIRootDir(), "dbaccess/ui/tabledesignrowmenu.ui", ""); + VclPtr aContextMenu(aBuilder.get_menu("menu")); + + aContextMenu->EnableItem(aContextMenu->GetItemId("cut"), IsCutAllowed()); + aContextMenu->EnableItem(aContextMenu->GetItemId("copy"), IsCopyAllowed()); + aContextMenu->EnableItem(aContextMenu->GetItemId("paste"), IsPasteAllowed()); + aContextMenu->EnableItem(aContextMenu->GetItemId("delete"), IsDeleteAllowed()); + aContextMenu->EnableItem(aContextMenu->GetItemId("primarykey"), IsPrimaryKeyAllowed()); + aContextMenu->EnableItem(aContextMenu->GetItemId("insert"), IsInsertNewAllowed(nRow)); + aContextMenu->CheckItem("primarykey", IsRowSelected(GetCurRow()) && IsPrimaryKey()); + + // remove all the disable entries + aContextMenu->RemoveDisabledEntries(true, true); + + 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(); + aContextMenu->Execute(this, aMenuPos); + OString sIdent = aContextMenu->GetCurItemIdent(); + 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& rxRow) { + return rxRow && rxRow->GetActFieldDescr() && !rxRow->GetActFieldDescr()->GetName().isEmpty(); }); + auto nFreeFromPos = static_cast(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 ) + { + long nIndex = FirstSelectedRow(); + while( nIndex != SFX_ENDOFSELECTION ) + { + // Set the key + std::shared_ptr pRow = (*m_pRowList)[nIndex]; + OFieldDescription* pFieldDescr = pRow->GetActFieldDescr(); + if(pFieldDescr) + AdjustFieldDescription(pFieldDescr,aInsertedPrimKeys,nIndex,false,true); + + nIndex = NextSelectedRow(); + } + } + + GetUndoManager().AddUndoAction( std::make_unique(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 ? + 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 + long nRow(GetCurRow()); + OFieldDescription* pActFieldDescr = GetFieldDescr( nRow ); + if( pActFieldDescr ) + // Store the old description + pDescrWin->SaveData( pActFieldDescr ); + + if ( nRow < 0 || nRow > static_cast(m_pRowList->size()) ) + return; + // Show the new description + std::shared_ptr 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 static_cast(GetParent()->GetParent()); +} + +void OTableEditorCtrl::DeactivateCell(bool bUpdate) +{ + OTableRowView::DeactivateCell(bUpdate); + // now we have to deactivate the field description + long 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..44469bf29 --- /dev/null +++ b/dbaccess/source/ui/tabledesign/TEditControl.hxx @@ -0,0 +1,205 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_TABLEDESIGN_TEDITCONTROL_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_TABLEDESIGN_TEDITCONTROL_HXX + +#include +#include +#include "TableFieldDescWin.hxx" +#include +#include + +class Edit; +class SfxUndoManager; +namespace dbaui +{ + class OSQLNameEdit; + + class OTableEditorCtrl : public OTableRowView + { + enum ChildFocusState + { + HELPTEXT, + DESCRIPTION, + NAME, + ROW, + NONE + }; + + std::vector< std::shared_ptr >* m_pRowList; + + VclPtr pNameCell; + VclPtr< ::svt::ListBoxControl> pTypeCell; + VclPtr pHelpTextCell; + VclPtr pDescrCell; + VclPtr pDescrWin; // properties of one column + + std::shared_ptr pActRow; + + ImplSVEvent * nCutEvent; + ImplSVEvent * nPasteEvent; + ImplSVEvent * nDeleteEvent; + ImplSVEvent * nInsNewRowsEvent; + ImplSVEvent * nInvalidateTypeEvent; + ChildFocusState m_eChildFocus; + + long nOldDataPos; + + bool bReadOnly; + + // helper class + class ClipboardInvalidator final + { + private: + AutoTimer m_aInvalidateTimer; + VclPtr 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(long nRow) override; + virtual void PaintCell(OutputDevice& rDev, const tools::Rectangle& rRect, + sal_uInt16 nColumnId ) const override; + + virtual void CursorMoved() override; + virtual RowStatus GetRowStatus(long nRow) const override; + + virtual ::svt::CellController* GetController(long nRow, sal_uInt16 nCol) override; + virtual void InitController(::svt::CellControllerRef& rController, long 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(long nRow, sal_uInt16 nColId) const override; + virtual sal_uInt32 GetTotalCellWidth(long nRow, sal_uInt16 nColId) override; + + virtual void CopyRows() override; + virtual void InsertRows( long nRow ) override; + virtual void DeleteRows() override; + virtual void InsertNewRows( long nRow ) override; + + virtual bool IsPrimaryKeyAllowed() override; + virtual bool IsInsertNewAllowed( long nRow ) override; + virtual bool IsDeleteAllowed() override; + + void ClearModified(); + + void SetPrimaryKey( bool bSet ); + bool IsPrimaryKey(); + + public: + explicit OTableEditorCtrl(vcl::Window* pParentWin); + virtual ~OTableEditorCtrl() override; + virtual void dispose() override; + virtual bool CursorMoving(long 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( long nRow ); + + virtual void SetCellData( long nRow, sal_uInt16 nColId, const TOTypeInfoSP& _pTypeInfo ) override; + virtual void SetCellData( long nRow, sal_uInt16 nColId, const css::uno::Any& _rSaveData ) override; + virtual css::uno::Any GetCellData( long nRow, sal_uInt16 nColId ) override; + virtual void SetControlText( long nRow, sal_uInt16 nColId, const OUString& rText ) override; + + virtual OTableDesignView* GetView() const override; + + std::vector< std::shared_ptr >* GetRowList(){ return m_pRowList; } + + const std::shared_ptr& GetActRow() const { return pActRow; } + void CellModified( long 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( long 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( const OUString& rFieldName ); + OUString GenerateName( const OUString& rName ); + bool SetDataPtr( long nRow ); + + void SaveData(long 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(); + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_UI_TABLEDESIGN_TEDITCONTROL_HXX + +/* 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..f88110b48 --- /dev/null +++ b/dbaccess/source/ui/tabledesign/TableController.cxx @@ -0,0 +1,1511 @@ +/* -*- 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 +#include "TEditControl.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +extern "C" void createRegistryInfo_OTableControl() +{ + static ::dbaui::OMultiInstanceAutoRegistration< ::dbaui::OTableController > aAutoRegistration; +} + +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& _rxTable,const OUString& _sTableName) + { + if ( _rxTable->hasByName(_sTableName) ) + { + Reference 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 getImplementationName_Static(); +} + +OUString OTableController::getImplementationName_Static() +{ + return "org.openoffice.comp.dbu.OTableDesign"; +} + +Sequence< OUString> OTableController::getSupportedServiceNames_Static() +{ + return { "com.sun.star.sdb.TableDesign" }; +} + +Sequence< OUString> SAL_CALL OTableController::getSupportedServiceNames() +{ + return getSupportedServiceNames_Static(); +} + +Reference< XInterface > OTableController::Create(const Reference& _rxFactory) +{ + return *(new OTableController(comphelper::getComponentContext(_rxFactory))); +} + +OTableController::OTableController(const Reference< XComponentContext >& _rM) : OTableController_BASE(_rM) + ,m_sTypeNames(DBA_RES(STR_TABLEDESIGN_DBFIELDTYPES)) + ,m_pTypeInfo() + ,m_bAllowAutoIncrementValue(false) + ,m_bNew(true) +{ + + InvalidateAll(); + m_pTypeInfo = std::make_shared(); + 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(this)); +} + +void OTableController::stopTableListening() +{ + Reference< XComponent > xComponent(m_xTable, UNO_QUERY); + if (xComponent.is()) + xComponent->removeEventListener(static_cast(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() && m_aCurrentFrame.isActive() && getView() && static_cast(getView())->isCutAllowed(); + break; + case ID_BROWSER_COPY: + aReturn.bEnabled = m_aCurrentFrame.isActive() && getView() && static_cast(getView())->isCopyAllowed(); + break; + case ID_BROWSER_PASTE: + aReturn.bEnabled = isEditable() && m_aCurrentFrame.isActive() && getView() && static_cast(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(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(getView())->GetEditorCtrl()->SaveCurRow(); + doSaveDoc(false); + break; + case ID_BROWSER_CUT: + static_cast(getView())->cut(); + break; + case ID_BROWSER_COPY: + static_cast(getView())->copy(); + break; + case ID_BROWSER_PASTE: + static_cast(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 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 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 xTable; + if(bNew || !xTables->hasByName(m_sName)) // just to make sure the table already exists + { + dropTable(xTables,m_sName); + + Reference 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,makeAny(sCatalog)); + xTable->setPropertyValue(PROPERTY_SCHEMANAME,makeAny(sSchema)); + xTable->setPropertyValue(PROPERTY_NAME,makeAny(m_sName)); + + // now append the columns + Reference xColSup(xTable,UNO_QUERY); + appendColumns(xColSup,bNew); + // now append the primary key + Reference xKeySup(xTable,UNO_QUERY); + appendPrimaryKey(xKeySup,bNew); + } + // now set the properties + if(bNew) + { + Reference 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 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::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(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 xBuilder(Application::CreateBuilder(getFrameWeld(), "dbaccess/ui/tabledesignsavemodifieddialog.ui")); + std::unique_ptr xQuery(xBuilder->weld_message_dialog("TableDesignSaveModifiedDialog")); + switch (xQuery->run()) + { + case RET_YES: + Execute(ID_BROWSER_SAVEDOC,Sequence()); + 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 xBuilder(Application::CreateBuilder(getFrameWeld(), "dbaccess/ui/deleteallrowsdialog.ui")); + std::unique_ptr xQuery(xBuilder->weld_message_dialog("DeleteAllRowsDialog")); + switch (xQuery->run()) + { + case RET_YES: + { + try + { + Reference xTablesSup(getConnection(),UNO_QUERY); + Reference 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 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 const & _rxColSup, bool _bNew, bool _bKeyColumns) +{ + try + { + // now append the columns + OSL_ENSURE(_rxColSup.is(),"No columns supplier"); + if(!_rxColSup.is()) + return; + Reference xColumns = _rxColSup->getColumns(); + OSL_ENSURE(xColumns.is(),"No columns"); + Reference xColumnFactory(xColumns,UNO_QUERY); + + Reference 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 xColumn; + if(pField->IsPrimaryKey() || !_bKeyColumns) + xColumn = xColumnFactory->createDataDescriptor(); + if(xColumn.is()) + { + if(!_bKeyColumns) + ::dbaui::setColumnProperties(xColumn,pField); + else + xColumn->setPropertyValue(PROPERTY_NAME,makeAny(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 const & _rxSup, bool _bNew) +{ + if(!_rxSup.is()) + return; // the database doesn't support keys + + OSL_ENSURE(_rxSup.is(),"No XKeysSupplier!"); + Reference xKeys = _rxSup->getKeys(); + Reference 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 xKeyFactory(xKeys,UNO_QUERY); + OSL_ENSURE(xKeyFactory.is(),"No XDataDescriptorFactory Interface!"); + if ( !xKeyFactory.is() ) + return; + Reference xAppend(xKeyFactory,UNO_QUERY); + OSL_ENSURE(xAppend.is(),"No XAppend Interface!"); + + Reference xKey = xKeyFactory->createDataDescriptor(); + OSL_ENSURE(xKey.is(),"Key is null!"); + xKey->setPropertyValue(PROPERTY_TYPE,makeAny(KeyType::PRIMARY)); + + Reference xColSup(xKey,UNO_QUERY); + if(xColSup.is()) + { + appendColumns(xColSup,_bNew,true); + Reference 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 pTabEdRow; + Reference< XDatabaseMetaData> xMetaData = getMetaData( ); + // fill data structure with data from DataDefinitionObject + if(m_xTable.is() && xMetaData.is()) + { + Reference xColSup(m_xTable,UNO_QUERY); + OSL_ENSURE(xColSup.is(),"No XColumnsSupplier!"); + Reference 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 aColNames = xColumns->getElementNames(); + for(const OUString& rColumn : aColNames) + { + Reference 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(); + pTabEdRow->SetReadOnly(!bIsAlterAllowed); + // search for type + bool bForce; + OUString const sCreate("x"); + TOTypeInfoSP pTypeInfo = ::dbaui::getTypeInfoFromType(m_aTypeInfo,nType,sTypeName,sCreate,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 xKeyColumns = getKeyColumns(); + if(xKeyColumns.is()) + { + const Sequence aKeyColumnNames = xKeyColumns->getElementNames(); + for(const OUString& rKeyColumn : aKeyColumnNames) + { + for(std::shared_ptr 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(); + pTabEdRow->SetReadOnly(bReadRow); + m_vRowList.push_back( pTabEdRow); + } +} + +Reference 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 >::const_iterator aIter = m_vRowList.begin(); + std::vector< std::shared_ptr >::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& 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(); + 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(getView())->GetEditorCtrl()->Invalidate(); + static_cast(getView())->GetEditorCtrl()->RowInserted(0); + } + break; + case RET_CANCEL: + bOk = false; + break; + } + } + return bOk; +} + +void OTableController::alterColumns() +{ + Reference xColSup(m_xTable,UNO_QUERY_THROW); + + Reference xColumns = xColSup->getColumns(); + Reference xIdxColumns(xColumns,UNO_QUERY_THROW); + OSL_ENSURE(xColumns.is(),"No columns"); + if ( !xColumns.is() ) + return; + Reference xAlter(m_xTable,UNO_QUERY); // can be null + + sal_Int32 nColumnCount = xIdxColumns->getCount(); + Reference xDrop(xColumns,UNO_QUERY); // can be null + Reference xAppend(xColumns,UNO_QUERY); // can be null + Reference 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 aColumns( + comphelper::UStringMixLess( + !xMetaData.is() + || xMetaData->supportsMixedCaseQuotedIdentifiers())); + std::vector< std::shared_ptr >::const_iterator aIter = m_vRowList.begin(); + std::vector< std::shared_ptr >::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 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 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 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 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 xColumn; + if ( xColumns->hasByName(pField->GetName()) ) + { + xColumns->getByName(pField->GetName()) >>= xColumn; + Reference xInfo = xColumn->getPropertySetInfo(); + if ( xInfo->hasPropertyByName(PROPERTY_HELPTEXT) ) + xColumn->setPropertyValue(PROPERTY_HELPTEXT,makeAny(pField->GetHelpText())); + + if(xInfo->hasPropertyByName(PROPERTY_CONTROLDEFAULT)) + xColumn->setPropertyValue(PROPERTY_CONTROLDEFAULT,pField->GetControlDefault()); + if(xInfo->hasPropertyByName(PROPERTY_FORMATKEY)) + xColumn->setPropertyValue(PROPERTY_FORMATKEY,makeAny(pField->GetFormatKey())); + if(xInfo->hasPropertyByName(PROPERTY_ALIGN)) + xColumn->setPropertyValue(PROPERTY_ALIGN,makeAny(dbaui::mapTextAllign(pField->GetHorJustify()))); + } + } + // second drop all columns which could be found by name + Reference xKeyColumns = getKeyColumns(); + // now we have to look for the columns who could be deleted + if ( xDrop.is() ) + { + const Sequence 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 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 xKeySup(m_xTable,UNO_QUERY); + Reference xKeys; + if(xKeySup.is()) + xKeys = xKeySup->getKeys(); + + if(xKeys.is()) + { + Reference 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(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; + Reference 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 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 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 xColsSup(m_xTable,UNO_QUERY); + bool bAddAllowed = !m_xTable.is(); + if(xColsSup.is()) + bAddAllowed = Reference(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 xColsSup(m_xTable,UNO_QUERY); + bool bDropAllowed = !m_xTable.is(); + if(xColsSup.is()) + { + Reference xNameAccess = xColsSup->getColumns(); + bDropAllowed = Reference(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(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(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& 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 = aName.getToken(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(getView())->reSync(); // show the windows and fill with our information + ClearUndoManager(); + setModified(false); // and we are not modified yet + static_cast(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(); + 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..2fe3e5ec9 --- /dev/null +++ b/dbaccess/source/ui/tabledesign/TableDesignControl.cxx @@ -0,0 +1,181 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include +#include + +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(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())); + long nRow = GetRowAtYPosPixel(rEvt.GetMousePosPixel().Y()); + + if ( nColId == HANDLE_ID ) + { + VclBuilder aBuilder(nullptr, VclBuilderContainer::getUIRootDir(), "dbaccess/ui/querycolmenu.ui", ""); + VclPtr aContextMenu(aBuilder.get_menu("menu")); + long nSelectRowCount = GetSelectRowCount(); + aContextMenu->EnableItem(aContextMenu->GetItemId("cut"), nSelectRowCount != 0); + aContextMenu->EnableItem(aContextMenu->GetItemId("copy"), nSelectRowCount != 0); + aContextMenu->EnableItem(aContextMenu->GetItemId("paste"), false); + aContextMenu->EnableItem(aContextMenu->GetItemId("delete"), false); + aContextMenu->Execute(this, rEvt.GetMousePosPixel()); + OString sIdent = aContextMenu->GetCurItemIdent(); + if (sIdent == "cut") + cut(); + else if (sIdent == "copy") + copy(); + else if (sIdent == "paste") + { + Paste( nRow ); + SetNoSelection(); + GoToRow( nRow ); + SeekRow( nRow ); + } + else if (sIdent == "delete") + DeleteRows(); + 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( long nRow ) +{ + InsertRows( nRow ); +} + +EditBrowseBox::RowStatus OTableRowView::GetRowStatus(long 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..3d73ff0e6 --- /dev/null +++ b/dbaccess/source/ui/tabledesign/TableDesignHelpBar.cxx @@ -0,0 +1,105 @@ +/* -*- 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 +#include +#include +#include +#include + +using namespace dbaui; +#define STANDARD_MARGIN 6 +OTableDesignHelpBar::OTableDesignHelpBar( vcl::Window* pParent ) : + TabPage( pParent, WB_3DLOOK ) +{ + m_pTextWin = VclPtr::Create( this, WB_VSCROLL | WB_LEFT | WB_BORDER | WB_NOTABSTOP | WB_READONLY); + m_pTextWin->SetHelpId(HID_TABLE_DESIGN_HELP_WINDOW); + m_pTextWin->SetReadOnly(); + m_pTextWin->SetControlBackground( GetSettings().GetStyleSettings().GetFaceColor() ); + m_pTextWin->Show(); +} + +OTableDesignHelpBar::~OTableDesignHelpBar() +{ + disposeOnce(); +} + +void OTableDesignHelpBar::dispose() +{ + m_pTextWin.disposeAndClear(); + TabPage::dispose(); +} + +void OTableDesignHelpBar::SetHelpText( const OUString& rText ) +{ + if(m_pTextWin) + m_pTextWin->SetText( rText ); + Invalidate(); +} + +void OTableDesignHelpBar::Resize() +{ + // parent window dimensions + Size aOutputSize( GetOutputSizePixel() ); + + // adapt the TextWin + if(m_pTextWin) + m_pTextWin->SetPosSizePixel( Point(STANDARD_MARGIN+1, STANDARD_MARGIN+1), + Size(aOutputSize.Width()-(2*STANDARD_MARGIN)-2, + aOutputSize.Height()-(2*STANDARD_MARGIN)-2) ); + +} + +bool OTableDesignHelpBar::PreNotify( NotifyEvent& rNEvt ) +{ + if (rNEvt.GetType() == MouseNotifyEvent::LOSEFOCUS) + SetHelpText(OUString()); + return TabPage::PreNotify(rNEvt); +} + +bool OTableDesignHelpBar::isCopyAllowed() +{ + return m_pTextWin && !m_pTextWin->GetSelected().isEmpty(); +} + +bool OTableDesignHelpBar::isCutAllowed() +{ + return false; +} + +bool OTableDesignHelpBar::isPasteAllowed() +{ + return false; +} + +void OTableDesignHelpBar::cut() +{ +} + +void OTableDesignHelpBar::copy() +{ + if ( m_pTextWin ) + m_pTextWin->Copy(); +} + +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..af223a287 --- /dev/null +++ b/dbaccess/source/ui/tabledesign/TableDesignView.cxx @@ -0,0 +1,302 @@ +/* -*- 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 +#include +#include +#include +#include "TEditControl.hxx" +#include "TableFieldDescWin.hxx" +#include +#include +#include +#include +#include + +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(vcl::Window* pParent) : Window(pParent,WB_BORDER) + ,m_aHorzSplitter( VclPtr::Create(this) ) +{ + + ImplInitSettings(); + // create children + m_pEditorCtrl = VclPtr::Create( this); + m_pFieldDescWin = VclPtr::Create( this ); + + m_pFieldDescWin->SetHelpId(HID_TAB_DESIGN_DESCWIN); + + // set depending windows and controls + m_pEditorCtrl->SetDescrWin(m_pFieldDescWin); + + // set up splitter + m_aHorzSplitter->SetSplitHdl( LINK(this, OTableBorderWindow, SplitHdl) ); + m_aHorzSplitter->Show(); +} + +OTableBorderWindow::~OTableBorderWindow() +{ + disposeOnce(); +} + +void OTableBorderWindow::dispose() +{ + // destroy children + // ::dbaui::notifySystemWindow(this,m_pFieldDescWin,::comphelper::mem_fun(&TaskPaneList::RemoveWindow)); + m_pEditorCtrl->Hide(); + m_pFieldDescWin->Hide(); + m_pEditorCtrl.disposeAndClear(); + m_pFieldDescWin.disposeAndClear(); + m_aHorzSplitter.disposeAndClear(); + vcl::Window::dispose(); +} + +void OTableBorderWindow::Resize() +{ + const long nSplitterHeight(3); + + // dimensions of parent window + Size aOutputSize( GetOutputSize() ); + long nOutputWidth = aOutputSize.Width(); + long nOutputHeight = aOutputSize.Height(); + long nSplitPos = m_aHorzSplitter->GetSplitPosPixel(); + + // shift range of the splitter is the middle third of the output + long nDragPosY = nOutputHeight/3; + long nDragSizeHeight = nOutputHeight/3; + m_aHorzSplitter->SetDragRectPixel( tools::Rectangle(Point(0,nDragPosY), Size(nOutputWidth,nDragSizeHeight) ), this ); + if( (nSplitPos < nDragPosY) || (nSplitPos > (nDragPosY+nDragSizeHeight)) ) + nSplitPos = nDragPosY+nDragSizeHeight-5; + + // set splitter + m_aHorzSplitter->SetPosSizePixel( Point( 0, nSplitPos ), Size(nOutputWidth, nSplitterHeight)); + m_aHorzSplitter->SetSplitPosPixel( nSplitPos ); + + // set window + m_pEditorCtrl->SetPosSizePixel( Point(0, 0), Size(nOutputWidth , nSplitPos) ); + + m_pFieldDescWin->SetPosSizePixel( Point(0, nSplitPos+nSplitterHeight), + Size(nOutputWidth, nOutputHeight-nSplitPos-nSplitterHeight) ); +} + +IMPL_LINK( OTableBorderWindow, SplitHdl, Splitter*, pSplit, void ) +{ + if(pSplit == m_aHorzSplitter.get()) + { + m_aHorzSplitter->SetPosPixel( Point( m_aHorzSplitter->GetPosPixel().X(),m_aHorzSplitter->GetSplitPosPixel() ) ); + Resize(); + } +} + +void OTableBorderWindow::ImplInitSettings() +{ + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + + // FIXME RenderContext + + vcl::Font aFont = rStyleSettings.GetAppFont(); + if ( IsControlFont() ) + aFont.Merge( GetControlFont() ); + SetPointFont(*this, aFont); + + Color aTextColor = rStyleSettings.GetButtonTextColor(); + if ( IsControlForeground() ) + aTextColor = GetControlForeground(); + SetTextColor( aTextColor ); + + if( IsControlBackground() ) + SetBackground( GetControlBackground() ); + else + SetBackground( rStyleSettings.GetFaceColor() ); +} + +void OTableBorderWindow::DataChanged( const DataChangedEvent& rDCEvt ) +{ + Window::DataChanged( rDCEvt ); + + if ( (rDCEvt.GetType() == DataChangedEventType::SETTINGS) && + (rDCEvt.GetFlags() & AllSettingsFlags::STYLE) ) + { + ImplInitSettings(); + Invalidate(); + } +} + +void OTableBorderWindow::GetFocus() +{ + Window::GetFocus(); + + // forward the focus to the current cell of the editor control + if (m_pEditorCtrl) + m_pEditorCtrl->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::Create(this); + 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 ) ); +} + +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 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..cbd99179c --- /dev/null +++ b/dbaccess/source/ui/tabledesign/TableFieldControl.cxx @@ -0,0 +1,144 @@ +/* -*- 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 +#include +#include "TEditControl.hxx" +#include +#include +#include +#include + +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(vcl::Window* pParent, OTableDesignHelpBar* pHelpBar) + : OFieldDescControl(nullptr, pParent, pHelpBar) +{ +} + +void OTableFieldControl::CellModified(long nRow, sal_uInt16 nColId ) +{ + GetCtrl()->CellModified(nRow,nColId); +} + +OTableEditorCtrl* OTableFieldControl::GetCtrl() const +{ + OTableDesignView* pDesignWin = static_cast(GetParent()->GetParent()->GetParent()->GetParent()); + OSL_ENSURE(pDesignWin,"no view!"); + return pDesignWin->GetEditorCtrl(); +} + +bool OTableFieldControl::IsReadOnly() +{ + bool bRead(GetCtrl()->IsReadOnly()); + if( !bRead ) + { + // The columns of a css::sdbcx::View could not be locked + Reference xTable = GetCtrl()->GetView()->getController().getTable(); + if(xTable.is() && ::comphelper::getString(xTable->getPropertyValue(PROPERTY_TYPE)) == "VIEW") + bRead = true; + else + { + std::shared_ptr 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 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..42697bdb7 --- /dev/null +++ b/dbaccess/source/ui/tabledesign/TableFieldControl.hxx @@ -0,0 +1,60 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_TABLEDESIGN_TABLEFIELDCONTROL_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_TABLEDESIGN_TABLEFIELDCONTROL_HXX + +#include + +namespace dbaui +{ + class OTableEditorCtrl; + class OTableDesignHelpBar; + // OTableFieldControl + class OTableFieldControl : public OFieldDescControl + { + OTableEditorCtrl* GetCtrl() const; + protected: + virtual void ActivateAggregate( EControlType eType ) override; + virtual void DeactivateAggregate( EControlType eType ) override; + // are to be implemented by the derived classes + virtual void CellModified(long 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( vcl::Window* pParent, OTableDesignHelpBar* pHelpBar); + + using OFieldDescControl::BoolStringPersistent; + using OFieldDescControl::BoolStringUI; + + virtual css::uno::Reference< css::sdbc::XDatabaseMetaData> getMetaData() override; + virtual css::uno::Reference< css::sdbc::XConnection> getConnection() override; + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_UI_TABLEDESIGN_TABLEFIELDCONTROL_HXX + +/* 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..950750794 --- /dev/null +++ b/dbaccess/source/ui/tabledesign/TableFieldDescWin.cxx @@ -0,0 +1,275 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#define STANDARD_MARGIN 6 +#define DETAILS_HEADER_HEIGHT 25 +#define CONTROL_SPACING_X 18 // 6 +#define CONTROL_SPACING_Y 5 +#define CONTROL_HEIGHT 20 +#define CONTROL_WIDTH_1 140 // 100 +#define CONTROL_WIDTH_3 250 +#define CONTROL_WIDTH_4 (CONTROL_WIDTH_3 - CONTROL_HEIGHT - 5) +#define DETAILS_OPT_PAGE_WIDTH (CONTROL_WIDTH_1 + CONTROL_SPACING_X + CONTROL_WIDTH_4 + 50) +#define DETAILS_OPT_PAGE_HEIGHT ((CONTROL_HEIGHT + CONTROL_SPACING_Y) * 5) +#define DETAILS_MIN_HELP_WIDTH 100 +#define DETAILS_OPT_HELP_WIDTH 200 +#define DETAILS_MIN_HELP_HEIGHT 50 +#define DETAILS_OPT_HELP_HEIGHT 100 + +using namespace dbaui; +OTableFieldDescWin::OTableFieldDescWin( vcl::Window* pParent) + : TabPage(pParent, WB_3DLOOK) + , m_eChildFocus(NONE) +{ + // Header + m_pHeader = VclPtr::Create( this, WB_CENTER ); + m_pHeader->SetText(DBA_RES(STR_TAB_PROPERTIES)); + m_pHeader->Show(); + + // HelpBar + m_pHelpBar = VclPtr::Create( this ); + m_pHelpBar->SetHelpId(HID_TAB_DESIGN_HELP_TEXT_FRAME); + m_pHelpBar->Show(); + + m_pGenPage = VclPtr::Create( this, m_pHelpBar ); + getGenPage()->SetHelpId( HID_TABLE_DESIGN_TABPAGE_GENERAL ); + getGenPage()->Show(); +} + +OTableFieldDescWin::~OTableFieldDescWin() +{ + disposeOnce(); +} + +void OTableFieldDescWin::dispose() +{ + // destroy children + m_pHelpBar->Hide(); + getGenPage()->Hide(); + m_pHeader->Hide(); + + m_pGenPage.disposeAndClear(); + m_pHeader.disposeAndClear(); + m_pHelpBar.disposeAndClear(); + TabPage::dispose(); +} + +void OTableFieldDescWin::Init() +{ + OSL_ENSURE(getGenPage() != nullptr, "OTableFieldDescWin::Init : ups ... no GenericPage ... this will crash ..."); + getGenPage()->Init(); +} + +void OTableFieldDescWin::SetReadOnly( bool bRead ) +{ + getGenPage()->SetReadOnly( bRead ); +} + +void OTableFieldDescWin::DisplayData( OFieldDescription* pFieldDescr ) +{ + getGenPage()->DisplayData( pFieldDescr ); +} + +void OTableFieldDescWin::SaveData( OFieldDescription* pFieldDescr ) +{ + getGenPage()->SaveData( pFieldDescr ); +} + +void OTableFieldDescWin::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& /*rRect*/) +{ + // 3D-line at the top window border + const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings(); + + rRenderContext.SetLineColor(rStyleSettings.GetLightColor()); + rRenderContext.DrawLine(Point(0,0), Point(GetSizePixel().Width(), 0)); + + // 3D-line for the separation of the header + rRenderContext.DrawLine(Point(3, DETAILS_HEADER_HEIGHT), Point(GetSizePixel().Width() - 6, DETAILS_HEADER_HEIGHT)); + rRenderContext.SetLineColor(rStyleSettings.GetShadowColor()); + rRenderContext.DrawLine(Point(3, DETAILS_HEADER_HEIGHT - 1), Point(GetSizePixel().Width() - 6, DETAILS_HEADER_HEIGHT - 1)); +} + +void OTableFieldDescWin::Resize() +{ + // dimensions of the parent window + Size aOutputSize( GetOutputSizePixel() ); + long nOutputWidth = aOutputSize.Width(); + long nOutputHeight = aOutputSize.Height(); + + // since the GenPage can scroll, but I can't, I position the HelpWindow, in case I become too slim, + // _below_ the Genpage, not on the right side. But before that I try to make it a bit smaller + + long nHelpX, nHelpY; + long nHelpWidth, nHelpHeight; + long nPageWidth, nPageHeight; + + // do both fit next to each other (margin + page + margin + help)? + if (STANDARD_MARGIN + DETAILS_OPT_PAGE_WIDTH + STANDARD_MARGIN + DETAILS_MIN_HELP_WIDTH <= nOutputWidth) + { // yes -> then we wonder if can give the help its optimum width + nHelpWidth = DETAILS_OPT_HELP_WIDTH; + nPageWidth = nOutputWidth - nHelpWidth - STANDARD_MARGIN - STANDARD_MARGIN; + if (nPageWidth < DETAILS_OPT_PAGE_WIDTH) + { // rather resize the help from its optimal width to its minimum width + long nTransfer = DETAILS_OPT_PAGE_WIDTH - nPageWidth; + nPageWidth += nTransfer; + nHelpWidth -= nTransfer; + } + nHelpX = nOutputWidth - nHelpWidth; + // the heights are simple in that case... + nHelpY = DETAILS_HEADER_HEIGHT + 1; + nHelpHeight = nOutputHeight - nHelpY; + nPageHeight = nOutputHeight - STANDARD_MARGIN - DETAILS_HEADER_HEIGHT - STANDARD_MARGIN; + } + else + { // doesn't work next to each other, thus below each other (margin + header + page + help) + if (STANDARD_MARGIN + DETAILS_HEADER_HEIGHT + DETAILS_OPT_PAGE_HEIGHT + DETAILS_MIN_HELP_HEIGHT <= nOutputHeight) + { // it's at least enough, to fit both below each other (page optimal, help minimal) + nHelpHeight = DETAILS_OPT_HELP_HEIGHT; + nPageHeight = nOutputHeight - nHelpHeight - DETAILS_HEADER_HEIGHT - STANDARD_MARGIN; + if (nPageHeight < DETAILS_OPT_PAGE_HEIGHT) + { // like above: page optimal, help gets whatever is left (which is bigger/equal to its minimum) + long nTransfer = DETAILS_OPT_PAGE_HEIGHT - nPageHeight; + nPageHeight += nTransfer; + nHelpHeight -= nTransfer; + } + nHelpY = nOutputHeight - nHelpHeight; + // and across the entire width + nHelpX = 0; // without margin, since the HelpCtrl has its own one + nHelpWidth = nOutputWidth; // dito + nPageWidth = nOutputWidth - STANDARD_MARGIN - STANDARD_MARGIN; + } + else + { // unfortunately that's not even enough, to show page at its optimum and help with minimum width + nHelpX = nHelpY = nHelpWidth = nHelpHeight = 0; // thus no help window + nPageWidth = nOutputWidth - STANDARD_MARGIN - STANDARD_MARGIN; + nPageHeight = nOutputHeight - STANDARD_MARGIN - DETAILS_HEADER_HEIGHT - STANDARD_MARGIN; + } + } + + m_pHeader->SetPosSizePixel( Point(0, STANDARD_MARGIN), Size(nOutputWidth, 15) ); + + getGenPage()->SetPosSizePixel(Point ( STANDARD_MARGIN, + STANDARD_MARGIN + DETAILS_HEADER_HEIGHT + ), + Size ( nPageWidth, + nPageHeight + ) + ); + if (nHelpHeight) + { + m_pHelpBar->Show(); + m_pHelpBar->SetPosSizePixel(Point ( nHelpX, + nHelpY + ), + Size ( nHelpWidth, + nHelpHeight + ) + ); + } + else + { + m_pHelpBar->Hide(); + } + Invalidate(); +} + +IClipboardTest* OTableFieldDescWin::getActiveChild() const +{ + IClipboardTest* pTest = nullptr; + switch(m_eChildFocus) + { + case DESCRIPTION: + pTest = getGenPage(); + break; + default: + pTest = m_pHelpBar; + break; + } + return pTest; +} + +bool OTableFieldDescWin::isCopyAllowed() +{ + return getActiveChild() && getActiveChild()->isCopyAllowed(); +} + +bool OTableFieldDescWin::isCutAllowed() +{ + return (getGenPage() && getGenPage()->HasChildPathFocus() && getGenPage()->isCutAllowed()); +} + +bool OTableFieldDescWin::isPasteAllowed() +{ + return (getGenPage() && getGenPage()->HasChildPathFocus() && getGenPage()->isPasteAllowed()); +} + +void OTableFieldDescWin::cut() +{ + if ( getGenPage() && getGenPage()->HasChildPathFocus() ) + getGenPage()->cut(); +} + +void OTableFieldDescWin::copy() +{ + if ( getActiveChild() ) + getActiveChild()->copy(); +} + +void OTableFieldDescWin::paste() +{ + if ( getGenPage() && getGenPage()->HasChildPathFocus() ) + getGenPage()->paste(); +} + +void OTableFieldDescWin::GetFocus() +{ + if ( getGenPage() ) + getGenPage()->GetFocus(); +} + +void OTableFieldDescWin::LoseFocus() +{ + if ( getGenPage() ) + getGenPage()->LoseFocus(); +} + +bool OTableFieldDescWin::PreNotify( NotifyEvent& rNEvt ) +{ + if (rNEvt.GetType() == MouseNotifyEvent::GETFOCUS) + { + if( getGenPage() && getGenPage()->HasChildPathFocus() ) + m_eChildFocus = DESCRIPTION; + else + m_eChildFocus = HELP; + } + return TabPage::PreNotify(rNEvt); +} + +/* 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..e85557f24 --- /dev/null +++ b/dbaccess/source/ui/tabledesign/TableFieldDescWin.hxx @@ -0,0 +1,95 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_TABLEDESIGN_TABLEFIELDDESCWIN_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_TABLEDESIGN_TABLEFIELDDESCWIN_HXX + +#include +#include "FieldDescGenWin.hxx" +#include + +class FixedText; +namespace dbaui +{ + class OFieldDescGenWin; + class OTableDesignHelpBar; + class OFieldDescription; + // derivative of TabPage is a trick of TH, + // to notice a change in system colours + class OTableFieldDescWin : public TabPage + ,public IClipboardTest + { + enum ChildFocusState + { + DESCRIPTION, + HELP, + NONE + }; + private: + VclPtr m_pHelpBar; + VclPtr m_pGenPage; + VclPtr m_pHeader; + ChildFocusState m_eChildFocus; + + IClipboardTest* getActiveChild() const; + + protected: + virtual void Resize() override; + virtual void Paint( vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect ) override; + + public: + explicit OTableFieldDescWin( vcl::Window* pParent); + virtual ~OTableFieldDescWin() override; + virtual void dispose() override; + + void Init(); + + void DisplayData( OFieldDescription* pFieldDescr ); + void SaveData( OFieldDescription* pFieldDescr ); + void SetReadOnly( bool bReadOnly ); + + // Window overrides + virtual bool PreNotify( NotifyEvent& rNEvt ) override; + virtual void GetFocus() override; + virtual void LoseFocus() override; + + void SetControlText( sal_uInt16 nControlId, const OUString& rText ) + { m_pGenPage->SetControlText(nControlId,rText); } + + // short GetFormatCategory(OFieldDescription* pFieldDescr) { return m_pGenPage ? m_pGenPage->GetFormatCategory(pFieldDescr) : -1; } + // delivers a CAT_xxx (CAT_NUMBER, CAT_DATE ...) value to a Format set in the field + + OUString BoolStringPersistent(const OUString& rUIString) const { return m_pGenPage->BoolStringPersistent(rUIString); } + OUString BoolStringUI(const OUString& rPersistentString) const { return m_pGenPage->BoolStringUI(rPersistentString); } + + // 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; + + OFieldDescGenWin* getGenPage() const { return m_pGenPage; } + + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_UI_TABLEDESIGN_TABLEFIELDDESCWIN_HXX + +/* 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..c84ebc834 --- /dev/null +++ b/dbaccess/source/ui/tabledesign/TableRow.cxx @@ -0,0 +1,193 @@ +/* -*- 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 +#include +#include +#include + +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 Reference< XPropertySet >& xAffectedCol) + :m_pActFieldDescr( nullptr ) + ,m_nPos( -1 ) + ,m_bReadOnly( false ) + ,m_bOwnsDescriptions(true) +{ + m_pActFieldDescr = new OFieldDescription(xAffectedCol); +} + +OTableRow::OTableRow( const OTableRow& rRow, 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(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 ) + { + 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(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..53b54cef4 --- /dev/null +++ b/dbaccess/source/ui/tabledesign/TableRowExchange.cxx @@ -0,0 +1,68 @@ +/* -*- 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 +#include +#include +#include + +namespace dbaui +{ + constexpr sal_uInt32 FORMAT_OBJECT_ID_SBA_TABED = 1; + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::beans; + OTableRowExchange::OTableRowExchange(const std::vector< std::shared_ptr >& _rvTableRow) + : m_vTableRow(_rvTableRow) + { + } + bool OTableRowExchange::WriteObject( tools::SvRef& rxOStm, void* pUserObject, sal_uInt32 nUserObjectId, const css::datatransfer::DataFlavor& /*rFlavor*/ ) + { + if(nUserObjectId == FORMAT_OBJECT_ID_SBA_TABED) + { + std::vector< std::shared_ptr >* pRows = static_cast< std::vector< std::shared_ptr >* >(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..3824880de --- /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 +#include "TEditControl.hxx" +#include +#include +#include +#include +#include + +using namespace dbaui; +using namespace ::svt; + + +OTableDesignUndoAct::OTableDesignUndoAct(OTableRowView* pOwner, const char* 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, long 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->ClearModified(); + 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, const char* pCommentID) + : OTableDesignUndoAct(pOwner, pCommentID) + , pTabEdCtrl(pOwner) +{ +} + +OTableEditorUndoAct::~OTableEditorUndoAct() +{ +} + +OTableEditorTypeSelUndoAct::OTableEditorTypeSelUndoAct( OTableEditorCtrl* pOwner, long 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 >* pOriginalRows = pOwner->GetRowList(); + sal_Int32 nIndex = pOwner->FirstSelectedRow(); + std::shared_ptr pOriginalRow; + std::shared_ptr pNewRow; + + while( nIndex != SFX_ENDOFSELECTION ) + { + pOriginalRow = (*pOriginalRows)[nIndex]; + pNewRow = std::make_shared( *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 pNewOrigRow; + std::vector< std::shared_ptr >* pOriginalRows = pTabEdCtrl->GetRowList(); + + for (auto const& deletedRow : m_aDeletedRows) + { + pNewOrigRow = std::make_shared( *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 >* 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, + long nInsertPosition , + const std::vector< std::shared_ptr >& _vInsertedRows) + :OTableEditorUndoAct( pOwner,STR_TABED_UNDO_ROWINSERTED ) + ,m_vInsertedRows(_vInsertedRows) + ,m_nInsPos( nInsertPosition ) +{ +} + +OTableEditorInsUndoAct::~OTableEditorInsUndoAct() +{ + m_vInsertedRows.clear(); +} + +void OTableEditorInsUndoAct::Undo() +{ + // delete lines again + std::vector< std::shared_ptr >* 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 + long nInsertRow = m_nInsPos; + std::shared_ptr pRow; + std::vector< std::shared_ptr >* pRowList = pTabEdCtrl->GetRowList(); + for (auto const& insertedRow : m_vInsertedRows) + { + pRow = std::make_shared( *insertedRow ); + pRowList->insert( pRowList->begin()+nInsertRow ,pRow ); + nInsertRow++; + } + + pTabEdCtrl->RowInserted( m_nInsPos, m_vInsertedRows.size() ); + pTabEdCtrl->InvalidateHandleColumn(); + + OTableEditorUndoAct::Redo(); +} + +OTableEditorInsNewUndoAct::OTableEditorInsNewUndoAct( OTableEditorCtrl* pOwner, long nInsertPosition, long 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 >* 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 >* pRowList = pTabEdCtrl->GetRowList(); + + for( long i=m_nInsPos; i<(m_nInsPos+m_nInsRows); i++ ) + pRowList->insert( pRowList->begin()+i,std::make_shared() ); + + 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 >* pRowList = pTabEdCtrl->GetRowList(); + std::shared_ptr pRow; + long nIndex; + + // delete inserted keys + for( nIndex = m_aInsKeys.FirstSelected(); nIndex != long(SFX_ENDOFSELECTION); nIndex=m_aInsKeys.NextSelected() ) + { + OSL_ENSURE(nIndex <= static_cast(pRowList->size()),"Index for undo isn't valid!"); + pRow = (*pRowList)[nIndex]; + pRow->SetPrimaryKey( false ); + } + + // restore deleted keys + for( nIndex = m_aDelKeys.FirstSelected(); nIndex != long(SFX_ENDOFSELECTION); nIndex=m_aDelKeys.NextSelected() ) + { + OSL_ENSURE(nIndex <= static_cast(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 >* pRowList = pTabEdCtrl->GetRowList(); + long nIndex; + + // delete the deleted keys + for( nIndex = m_aDelKeys.FirstSelected(); nIndex != long(SFX_ENDOFSELECTION); nIndex=m_aDelKeys.NextSelected() ) + (*pRowList)[nIndex]->SetPrimaryKey( false ); + + // restore the inserted keys + for( nIndex = m_aInsKeys.FirstSelected(); nIndex != 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..d4beb0f53 --- /dev/null +++ b/dbaccess/source/ui/tabledesign/TableUndo.hxx @@ -0,0 +1,138 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_TABLEDESIGN_TABLEUNDO_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_TABLEDESIGN_TABLEUNDO_HXX + +#include +#include + +#include + +#include +#include +#include + +namespace dbaui +{ + class OTableRowView; + class OTableRow; + class OTableDesignUndoAct : public OCommentUndoAction + { + protected: + VclPtr m_pTabDgnCtrl; + + virtual void Undo() override; + virtual void Redo() override; + public: + OTableDesignUndoAct(OTableRowView* pOwner, const char* pCommentID); + virtual ~OTableDesignUndoAct() override; + }; + + class OTableEditorCtrl; + class OTableEditorUndoAct : public OTableDesignUndoAct + { + protected: + VclPtr pTabEdCtrl; + + public: + OTableEditorUndoAct(OTableEditorCtrl* pOwner, const char* pCommentID); + virtual ~OTableEditorUndoAct() override; + }; + + class OTableDesignCellUndoAct final : public OTableDesignUndoAct + { + sal_uInt16 m_nCol; + long m_nRow; + css::uno::Any m_sOldText; + css::uno::Any m_sNewText; + + virtual void Undo() override; + virtual void Redo() override; + public: + OTableDesignCellUndoAct( OTableRowView* pOwner, long nRowID, sal_uInt16 nColumn ); + virtual ~OTableDesignCellUndoAct() override; + }; + + class OTableEditorTypeSelUndoAct final : public OTableEditorUndoAct + { + sal_uInt16 m_nCol; + long m_nRow; + TOTypeInfoSP m_pOldType; + TOTypeInfoSP m_pNewType; + + virtual void Undo() override; + virtual void Redo() override; + public: + OTableEditorTypeSelUndoAct( OTableEditorCtrl* pOwner, long nRowID, sal_uInt16 nColumn, const TOTypeInfoSP& _pOldType ); + virtual ~OTableEditorTypeSelUndoAct() override; + }; + + class OTableEditorDelUndoAct final : public OTableEditorUndoAct + { + std::vector< std::shared_ptr > 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 > m_vInsertedRows; + long m_nInsPos; + + virtual void Undo() override; + virtual void Redo() override; + public: + OTableEditorInsUndoAct( OTableEditorCtrl* pOwner, + long nInsertPosition, + const std::vector< std::shared_ptr >& _vInsertedRows); + virtual ~OTableEditorInsUndoAct() override; + }; + + class OTableEditorInsNewUndoAct final : public OTableEditorUndoAct + { + long m_nInsPos; + long m_nInsRows; + + virtual void Undo() override; + virtual void Redo() override; + public: + OTableEditorInsNewUndoAct( OTableEditorCtrl* pOwner, long nInsertPosition, long nInsertedRows ); + virtual ~OTableEditorInsNewUndoAct() override; + }; + + class OPrimKeyUndoAct final : public OTableEditorUndoAct + { + MultiSelection m_aDelKeys, + m_aInsKeys; + VclPtr m_pEditorCtrl; + + virtual void Undo() override; + virtual void Redo() override; + public: + OPrimKeyUndoAct( OTableEditorCtrl* pOwner, const MultiSelection& aDeletedKeys, const MultiSelection& aInsertedKeys ); + virtual ~OPrimKeyUndoAct() override; + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_UI_TABLEDESIGN_TABLEUNDO_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ -- cgit v1.2.3