diff options
Diffstat (limited to 'dbaccess/source/ui/misc')
29 files changed, 11284 insertions, 0 deletions
diff --git a/dbaccess/source/ui/misc/DExport.cxx b/dbaccess/source/ui/misc/DExport.cxx new file mode 100644 index 000000000..4f25bb467 --- /dev/null +++ b/dbaccess/source/ui/misc/DExport.cxx @@ -0,0 +1,840 @@ +/* -*- 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 <DExport.hxx> +#include <core_resource.hxx> + +#include <com/sun/star/sdbcx/XTablesSupplier.hpp> +#include <com/sun/star/sdbcx/XColumnsSupplier.hpp> +#include <com/sun/star/sdbc/DataType.hpp> +#include <com/sun/star/sdbc/ColumnValue.hpp> +#include <com/sun/star/sdb/CommandType.hpp> +#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/util/NumberFormat.hpp> +#include <com/sun/star/util/XNumberFormatTypes.hpp> +#include <strings.hrc> +#include <strings.hxx> +#include <connectivity/dbconversion.hxx> +#include <sal/log.hxx> +#include <sfx2/sfxhtml.hxx> +#include <svl/numuno.hxx> +#include <connectivity/dbtools.hxx> +#include <TypeInfo.hxx> +#include <FieldDescriptions.hxx> +#include <UITools.hxx> +#include <tools/diagnose_ex.h> +#include <com/sun/star/awt/FontDescriptor.hpp> +#include <WCopyTable.hxx> +#include <unotools/syslocale.hxx> +#include <svl/numformat.hxx> +#include <connectivity/dbexception.hxx> +#include <connectivity/FValue.hxx> +#include <com/sun/star/sdb/application/CopyTableOperation.hpp> +#include <sqlmessage.hxx> +#include "UpdateHelperImpl.hxx" +#include <cppuhelper/exc_hlp.hxx> + +using namespace dbaui; +using namespace utl; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::sdb; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::awt; + +namespace CopyTableOperation = ::com::sun::star::sdb::application::CopyTableOperation; + +// ODatabaseExport +ODatabaseExport::ODatabaseExport(sal_Int32 nRows, + TPositions&&_rColumnPositions, + const Reference< XNumberFormatter >& _rxNumberF, + const Reference< css::uno::XComponentContext >& _rxContext, + const TColumnVector* pList, + const OTypeInfoMap* _pInfoMap, + bool _bAutoIncrementEnabled, + SvStream& _rInputStream) + :m_vColumnPositions(std::move(_rColumnPositions)) + ,m_aDestColumns(true) + ,m_xFormatter(_rxNumberF) + ,m_xContext(_rxContext) + ,m_pFormatter(nullptr) + ,m_rInputStream( _rInputStream ) + ,m_pColumnList(pList) + ,m_pInfoMap(_pInfoMap) + ,m_nColumnPos(0) + ,m_nRows(1) + ,m_nRowCount(0) + ,m_bError(false) + ,m_bInTbl(false) + ,m_bHead(true) + ,m_bDontAskAgain(false) + ,m_bIsAutoIncrement(_bAutoIncrementEnabled) + ,m_bFoundTable(false) + ,m_bCheckOnly(false) + ,m_bAppendFirstLine(false) +{ + m_nRows += nRows; + sal_Int32 nCount = 0; + for(const std::pair<sal_Int32,sal_Int32> & rPair : m_vColumnPositions) + if ( rPair.first != COLUMN_POSITION_NOT_FOUND ) + ++nCount; + + m_vColumnSize.resize(nCount); + m_vNumberFormat.resize(nCount); + for(sal_Int32 i=0;i<nCount;++i) + { + m_vColumnSize[i] = 0; + m_vNumberFormat[i] = 0; + } + + try + { + SvtSysLocale aSysLocale; + m_aLocale = aSysLocale.GetLanguageTag().getLocale(); + } + catch(Exception&) + { + } + + SetColumnTypes(pList,_pInfoMap); +} + +ODatabaseExport::ODatabaseExport(const SharedConnection& _rxConnection, + const Reference< XNumberFormatter >& _rxNumberF, + const Reference< css::uno::XComponentContext >& _rxContext, + SvStream& _rInputStream) + :m_aDestColumns(_rxConnection->getMetaData().is() && _rxConnection->getMetaData()->supportsMixedCaseQuotedIdentifiers()) + ,m_xConnection(_rxConnection) + ,m_xFormatter(_rxNumberF) + ,m_xContext(_rxContext) + ,m_pFormatter(nullptr) + ,m_rInputStream( _rInputStream ) + ,m_pColumnList(nullptr) + ,m_pInfoMap(nullptr) + ,m_nColumnPos(0) + ,m_nRows(1) + ,m_nRowCount(0) + ,m_bError(false) + ,m_bInTbl(false) + ,m_bHead(true) + ,m_bDontAskAgain(false) + ,m_bIsAutoIncrement(false) + ,m_bFoundTable(false) + ,m_bCheckOnly(false) + ,m_bAppendFirstLine(false) +{ + try + { + SvtSysLocale aSysLocale; + m_aLocale = aSysLocale.GetLanguageTag().getLocale(); + } + catch(Exception&) + { + } + + Reference<XTablesSupplier> xTablesSup(m_xConnection,UNO_QUERY); + if(xTablesSup.is()) + m_xTables = xTablesSup->getTables(); + + Reference<XDatabaseMetaData> xMeta = m_xConnection->getMetaData(); + Reference<XResultSet> xSet = xMeta.is() ? xMeta->getTypeInfo() : Reference<XResultSet>(); + if(xSet.is()) + { + ::connectivity::ORowSetValue aValue; + std::vector<sal_Int32> aTypes; + std::vector<bool> aNullable; + Reference<XResultSetMetaData> xResultSetMetaData = Reference<XResultSetMetaDataSupplier>(xSet,UNO_QUERY_THROW)->getMetaData(); + Reference<XRow> xRow(xSet,UNO_QUERY_THROW); + while(xSet->next()) + { + if ( aTypes.empty() ) + { + sal_Int32 nCount = xResultSetMetaData->getColumnCount(); + if ( nCount < 1 ) + nCount = 18; + aTypes.reserve(nCount+1); + aNullable.reserve(nCount+1); + aTypes.push_back(-1); + aNullable.push_back(false); + for (sal_Int32 j = 1; j <= nCount ; ++j) + { + aNullable.push_back(xResultSetMetaData->isNullable(j) != ColumnValue::NO_NULLS ); + aTypes.push_back(xResultSetMetaData->getColumnType(j)); + } + } + + sal_Int32 nPos = 1; + OSL_ENSURE((nPos) < static_cast<sal_Int32>(aTypes.size()),"aTypes: Illegal index for vector"); + aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); + OUString sTypeName = aValue.getString(); + ++nPos; + OSL_ENSURE((nPos) < static_cast<sal_Int32>(aTypes.size()),"aTypes: Illegal index for vector"); + aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); + sal_Int32 nType = aValue.getInt32(); + ++nPos; + + if( nType == DataType::VARCHAR ) + { + m_pTypeInfo = std::make_shared<OTypeInfo>(); + + m_pTypeInfo->aTypeName = sTypeName; + m_pTypeInfo->nType = nType; + + OSL_ENSURE((nPos) < static_cast<sal_Int32>(aTypes.size()),"aTypes: Illegal index for vector"); + aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); + m_pTypeInfo->nPrecision = aValue.getInt32(); + ++nPos; + aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); //LiteralPrefix + ++nPos; + aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); //LiteralSuffix + ++nPos; + aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); + m_pTypeInfo->aCreateParams = aValue.getString(); + ++nPos; + aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); + m_pTypeInfo->bNullable = aValue.getInt32() == ColumnValue::NULLABLE; + ++nPos; + aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); + // bCaseSensitive + ++nPos; + aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); + m_pTypeInfo->nSearchType = aValue.getInt16(); + ++nPos; + aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); + // bUnsigned + ++nPos; + aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); + m_pTypeInfo->bCurrency = aValue.getBool(); + ++nPos; + aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); + m_pTypeInfo->bAutoIncrement = aValue.getBool(); + ++nPos; + aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); + m_pTypeInfo->aLocalTypeName = aValue.getString(); + ++nPos; + aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); + m_pTypeInfo->nMinimumScale = aValue.getInt16(); + ++nPos; + aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); + m_pTypeInfo->nMaximumScale = aValue.getInt16(); + nPos = 18; + aValue.fill(nPos,aTypes[nPos],xRow); + m_pTypeInfo->nNumPrecRadix = aValue.getInt32(); + + // check if values are less than zero like it happens in a oracle jdbc driver + if( m_pTypeInfo->nPrecision < 0) + m_pTypeInfo->nPrecision = 0; + if( m_pTypeInfo->nMinimumScale < 0) + m_pTypeInfo->nMinimumScale = 0; + if( m_pTypeInfo->nMaximumScale < 0) + m_pTypeInfo->nMaximumScale = 0; + if( m_pTypeInfo->nNumPrecRadix <= 1) + m_pTypeInfo->nNumPrecRadix = 10; + break; + } + } + } + if ( !m_pTypeInfo ) + m_pTypeInfo = std::make_shared<OTypeInfo>(); +} + +ODatabaseExport::~ODatabaseExport() +{ + m_pFormatter = nullptr; + for (auto const& destColumn : m_aDestColumns) + delete destColumn.second; + m_vDestVector.clear(); + m_aDestColumns.clear(); +} + +void ODatabaseExport::insertValueIntoColumn() +{ + if(m_nColumnPos >= sal_Int32(m_vDestVector.size())) + return; + + OFieldDescription* pField = m_vDestVector[m_nColumnPos]->second; + if(!pField) + return; + + sal_Int32 nNewPos = m_bIsAutoIncrement ? m_nColumnPos+1 : m_nColumnPos; + OSL_ENSURE(nNewPos < static_cast<sal_Int32>(m_vColumnPositions.size()),"m_vColumnPositions: Illegal index for vector"); + + if ( nNewPos < static_cast<sal_Int32>(m_vColumnPositions.size() ) ) + { + sal_Int32 nPos = m_vColumnPositions[nNewPos].first; + if ( nPos != COLUMN_POSITION_NOT_FOUND ) + { + if ( m_sTextToken.isEmpty() && pField->IsNullable() ) + m_pUpdateHelper->updateNull(nPos,pField->GetType()); + else + { + OSL_ENSURE((nNewPos) < static_cast<sal_Int32>(m_vColumnTypes.size()),"Illegal index for vector"); + if (m_vColumnTypes[nNewPos] != DataType::VARCHAR && m_vColumnTypes[nNewPos] != DataType::CHAR && m_vColumnTypes[nNewPos] != DataType::LONGVARCHAR ) + { + SAL_INFO("dbaccess.ui", "ODatabaseExport::insertValueIntoColumn != DataType::VARCHAR" ); + ensureFormatter(); + sal_Int32 nNumberFormat = 0; + double fOutNumber = 0.0; + bool bNumberFormatError = false; + if ( m_pFormatter && !m_sNumToken.isEmpty() ) + { + LanguageType eNumLang = LANGUAGE_NONE; + sal_uInt32 nNumberFormat2( nNumberFormat ); + fOutNumber = SfxHTMLParser::GetTableDataOptionsValNum(nNumberFormat2,eNumLang,m_sTextToken,m_sNumToken,*m_pFormatter); + if ( eNumLang != LANGUAGE_NONE ) + { + nNumberFormat2 = m_pFormatter->GetFormatForLanguageIfBuiltIn( nNumberFormat2, eNumLang ); + (void)m_pFormatter->IsNumberFormat( m_sTextToken, nNumberFormat2, fOutNumber ); + } + nNumberFormat = static_cast<sal_Int32>(nNumberFormat2); + } + else + { + Reference< XNumberFormatsSupplier > xSupplier = m_xFormatter->getNumberFormatsSupplier(); + Reference<XNumberFormatTypes> xNumType(xSupplier->getNumberFormats(),UNO_QUERY); + const sal_Int16 nFormats[] = { + NumberFormat::DATETIME + ,NumberFormat::DATE + ,NumberFormat::TIME + ,NumberFormat::CURRENCY + ,NumberFormat::NUMBER + ,NumberFormat::LOGICAL + }; + for (short nFormat : nFormats) + { + try + { + nNumberFormat = m_xFormatter->detectNumberFormat(xNumType->getStandardFormat(nFormat,m_aLocale),m_sTextToken); + break; + } + catch(Exception&) + { + } + } + try + { + fOutNumber = m_xFormatter->convertStringToNumber(nNumberFormat,m_sTextToken); + } + catch(Exception&) + { + bNumberFormatError = true; + m_pUpdateHelper->updateString(nPos,m_sTextToken); + } + } + if ( !bNumberFormatError ) + { + try + { + Reference< XNumberFormatsSupplier > xSupplier = m_xFormatter->getNumberFormatsSupplier(); + Reference< XNumberFormats > xFormats = xSupplier->getNumberFormats(); + Reference<XPropertySet> xProp = xFormats->getByKey(nNumberFormat); + sal_Int16 nType = 0; + xProp->getPropertyValue(PROPERTY_TYPE) >>= nType; + switch(nType) + { + case NumberFormat::DATE: + m_pUpdateHelper->updateDate(nPos,::dbtools::DBTypeConversion::toDate(fOutNumber,m_aNullDate)); + break; + case NumberFormat::DATETIME: + m_pUpdateHelper->updateTimestamp(nPos,::dbtools::DBTypeConversion::toDateTime(fOutNumber,m_aNullDate)); + break; + case NumberFormat::TIME: + m_pUpdateHelper->updateTime(nPos,::dbtools::DBTypeConversion::toTime(fOutNumber)); + break; + default: + m_pUpdateHelper->updateDouble(nPos,fOutNumber); + } + } + catch(Exception&) + { + m_pUpdateHelper->updateString(nPos,m_sTextToken); + } + } + + } + else + m_pUpdateHelper->updateString(nPos,m_sTextToken); + } + } + } + eraseTokens(); +} + +sal_Int16 ODatabaseExport::CheckString(const OUString& aCheckToken, sal_Int16 _nOldNumberFormat) +{ + sal_Int16 nNumberFormat = 0; + + try + { + Reference< XNumberFormatsSupplier > xSupplier = m_xFormatter->getNumberFormatsSupplier(); + Reference< XNumberFormats > xFormats = xSupplier->getNumberFormats(); + + ensureFormatter(); + if ( m_pFormatter && !m_sNumToken.isEmpty() ) + { + LanguageType eNumLang; + sal_uInt32 nFormatKey(0); + double fOutNumber = SfxHTMLParser::GetTableDataOptionsValNum(nFormatKey,eNumLang,m_sTextToken,m_sNumToken,*m_pFormatter); + if ( eNumLang != LANGUAGE_NONE ) + { + nFormatKey = m_pFormatter->GetFormatForLanguageIfBuiltIn( nFormatKey, eNumLang ); + if ( !m_pFormatter->IsNumberFormat( m_sTextToken, nFormatKey, fOutNumber ) ) + return NumberFormat::TEXT; + } + Reference<XPropertySet> xProp = xFormats->getByKey(nFormatKey); + xProp->getPropertyValue(PROPERTY_TYPE) >>= nNumberFormat; + } + else + { + Reference<XNumberFormatTypes> xNumType(xFormats,UNO_QUERY); + sal_Int32 nFormatKey = m_xFormatter->detectNumberFormat(xNumType->getStandardFormat(NumberFormat::ALL,m_aLocale),aCheckToken); + m_xFormatter->convertStringToNumber(nFormatKey,aCheckToken); + + Reference<XPropertySet> xProp = xFormats->getByKey(nFormatKey); + sal_Int16 nType = 0; + xProp->getPropertyValue(PROPERTY_TYPE) >>= nType; + + switch(nType) + { + case NumberFormat::ALL: + nNumberFormat = NumberFormat::ALL; + break; + case NumberFormat::DEFINED: + nNumberFormat = NumberFormat::TEXT; + break; + case NumberFormat::DATE: + switch(_nOldNumberFormat) + { + case NumberFormat::DATETIME: + case NumberFormat::TEXT: + case NumberFormat::DATE: + nNumberFormat = _nOldNumberFormat; + break; + case NumberFormat::ALL: + nNumberFormat = NumberFormat::DATE; + break; + default: + nNumberFormat = NumberFormat::TEXT; + + } + break; + case NumberFormat::TIME: + switch(_nOldNumberFormat) + { + case NumberFormat::DATETIME: + case NumberFormat::TEXT: + case NumberFormat::TIME: + nNumberFormat = _nOldNumberFormat; + break; + case NumberFormat::ALL: + nNumberFormat = NumberFormat::TIME; + break; + default: + nNumberFormat = NumberFormat::TEXT; + break; + } + break; + case NumberFormat::CURRENCY: + switch(_nOldNumberFormat) + { + case NumberFormat::NUMBER: + nNumberFormat = NumberFormat::CURRENCY; + break; + case NumberFormat::CURRENCY: + nNumberFormat = _nOldNumberFormat; + break; + case NumberFormat::ALL: + nNumberFormat = NumberFormat::CURRENCY; + break; + default: + nNumberFormat = NumberFormat::TEXT; + break; + } + break; + case NumberFormat::NUMBER: + case NumberFormat::SCIENTIFIC: + case NumberFormat::FRACTION: + case NumberFormat::PERCENT: + switch(_nOldNumberFormat) + { + case NumberFormat::NUMBER: + nNumberFormat = _nOldNumberFormat; + break; + case NumberFormat::CURRENCY: + nNumberFormat = NumberFormat::CURRENCY; + break; + case NumberFormat::ALL: + nNumberFormat = nType; + break; + default: + nNumberFormat = NumberFormat::TEXT; + break; + } + break; + case NumberFormat::TEXT: + case NumberFormat::UNDEFINED: + case NumberFormat::LOGICAL: + nNumberFormat = NumberFormat::TEXT; // Text overwrites everything + break; + case NumberFormat::DATETIME: + switch(_nOldNumberFormat) + { + case NumberFormat::DATETIME: + case NumberFormat::TEXT: + case NumberFormat::TIME: + nNumberFormat = _nOldNumberFormat; + break; + case NumberFormat::ALL: + nNumberFormat = NumberFormat::DATETIME; + break; + default: + nNumberFormat = NumberFormat::TEXT; + break; + } + break; + default: + SAL_WARN("dbaccess.ui", "ODatabaseExport: Unknown NumberFormat"); + } + } + } + catch(Exception&) + { + nNumberFormat = NumberFormat::TEXT; // Text overwrites everything + } + + return nNumberFormat; +} + +void ODatabaseExport::SetColumnTypes(const TColumnVector* _pList,const OTypeInfoMap* _pInfoMap) +{ + if(!(_pList && _pInfoMap)) + return; + + OSL_ENSURE(m_vNumberFormat.size() == m_vColumnSize.size() && m_vColumnSize.size() == _pList->size(),"Illegal columns in list"); + Reference< XNumberFormatsSupplier > xSupplier = m_xFormatter->getNumberFormatsSupplier(); + Reference< XNumberFormats > xFormats = xSupplier->getNumberFormats(); + sal_Int32 minBothSize = std::min<sal_Int32>(m_vNumberFormat.size(), m_vColumnSize.size()); + sal_Int32 i = 0; + for (auto const& elem : *_pList) + { + if (i >= minBothSize) + break; + + sal_Int32 nDataType; + sal_Int32 nLength(0),nScale(0); + sal_Int16 nType = m_vNumberFormat[i] & ~NumberFormat::DEFINED; + + switch ( nType ) + { + case NumberFormat::ALL: + nDataType = DataType::DOUBLE; + break; + case NumberFormat::DEFINED: + nDataType = DataType::VARCHAR; + nLength = ((m_vColumnSize[i] % 10 ) ? m_vColumnSize[i]/ 10 + 1: m_vColumnSize[i]/ 10) * 10; + break; + case NumberFormat::DATE: + nDataType = DataType::DATE; + break; + case NumberFormat::TIME: + nDataType = DataType::TIME; + break; + case NumberFormat::DATETIME: + nDataType = DataType::TIMESTAMP; + break; + case NumberFormat::CURRENCY: + nDataType = DataType::NUMERIC; + nScale = 4; + nLength = 19; + break; + case NumberFormat::NUMBER: + case NumberFormat::SCIENTIFIC: + case NumberFormat::FRACTION: + case NumberFormat::PERCENT: + nDataType = DataType::DOUBLE; + break; + case NumberFormat::TEXT: + case NumberFormat::UNDEFINED: + case NumberFormat::LOGICAL: + default: + nDataType = DataType::VARCHAR; + nLength = ((m_vColumnSize[i] % 10 ) ? m_vColumnSize[i]/ 10 + 1: m_vColumnSize[i]/ 10) * 10; + break; + } + OTypeInfoMap::const_iterator aFind = _pInfoMap->find(nDataType); + if(aFind != _pInfoMap->end()) + { + elem->second->SetType(aFind->second); + elem->second->SetPrecision(std::min<sal_Int32>(aFind->second->nPrecision,nLength)); + elem->second->SetScale(std::min<sal_Int32>(aFind->second->nMaximumScale,nScale)); + + sal_Int32 nFormatKey = ::dbtools::getDefaultNumberFormat( nDataType, + elem->second->GetScale(), + elem->second->IsCurrency(), + Reference< XNumberFormatTypes>(xFormats,UNO_QUERY), + m_aLocale); + + elem->second->SetFormatKey(nFormatKey); + } + ++i; + } +} + +void ODatabaseExport::CreateDefaultColumn(const OUString& _rColumnName) +{ + Reference< XDatabaseMetaData> xDestMetaData(m_xConnection->getMetaData()); + sal_Int32 nMaxNameLen(xDestMetaData->getMaxColumnNameLength()); + OUString aAlias = _rColumnName; + if ( isSQL92CheckEnabled(m_xConnection) ) + aAlias = ::dbtools::convertName2SQLName(_rColumnName,xDestMetaData->getExtraNameCharacters()); + + if(nMaxNameLen && aAlias.getLength() > nMaxNameLen) + aAlias = aAlias.copy(0, std::min<sal_Int32>( nMaxNameLen-1, aAlias.getLength() ) ); + + OUString sName(aAlias); + if(m_aDestColumns.find(sName) != m_aDestColumns.end()) + { + sal_Int32 nPos = 0; + sal_Int32 nCount = 2; + while(m_aDestColumns.find(sName) != m_aDestColumns.end()) + { + sName = aAlias + + OUString::number(++nPos); + if(nMaxNameLen && sName.getLength() > nMaxNameLen) + { + aAlias = aAlias.copy(0,std::min<sal_Int32>( nMaxNameLen-nCount, aAlias.getLength() )); + sName = aAlias + + OUString::number(nPos); + ++nCount; + } + } + } + aAlias = sName; + // now create a column + OFieldDescription* pField = new OFieldDescription(); + pField->SetType(m_pTypeInfo); + pField->SetName(aAlias); + pField->SetPrecision(std::min<sal_Int32>(sal_Int32(255),m_pTypeInfo->nPrecision)); + pField->SetScale(0); + pField->SetIsNullable(ColumnValue::NULLABLE); + pField->SetAutoIncrement(false); + pField->SetPrimaryKey(false); + pField->SetCurrency(false); + + TColumns::const_iterator aFind = m_aDestColumns.find( aAlias ); + if ( aFind != m_aDestColumns.end() ) + { + delete aFind->second; + m_aDestColumns.erase(aFind); + } + + m_vDestVector.emplace_back(m_aDestColumns.emplace(aAlias,pField).first); +} + +void ODatabaseExport::createRowSet() +{ + m_pUpdateHelper = std::make_shared<OParameterUpdateHelper>(createPreparedStatment(m_xConnection->getMetaData(),m_xTable,m_vColumnPositions)); +} + +bool ODatabaseExport::executeWizard(const OUString& _rTableName, const Any& _aTextColor, const FontDescriptor& _rFont) +{ + bool bHaveDefaultTable = !m_sDefaultTableName.isEmpty(); + OUString sTableName( bHaveDefaultTable ? m_sDefaultTableName : _rTableName ); + OCopyTableWizard aWizard( + nullptr, + sTableName, + bHaveDefaultTable ? CopyTableOperation::AppendData : CopyTableOperation::CopyDefinitionAndData, + ODatabaseExport::TColumns(m_aDestColumns), + m_vDestVector, + m_xConnection, + m_xFormatter, + getTypeSelectionPageFactory(), + m_rInputStream, + m_xContext + ); + + bool bError = false; + try + { + if (aWizard.run()) + { + switch(aWizard.getOperation()) + { + case CopyTableOperation::CopyDefinitionAndData: + case CopyTableOperation::AppendData: + { + m_xTable = aWizard.returnTable(); + bError = !m_xTable.is(); + if(m_xTable.is()) + { + m_xTable->setPropertyValue(PROPERTY_FONT,Any(_rFont)); + if(_aTextColor.hasValue()) + m_xTable->setPropertyValue(PROPERTY_TEXTCOLOR,_aTextColor); + } + m_bIsAutoIncrement = aWizard.shouldCreatePrimaryKey(); + m_vColumnPositions = aWizard.GetColumnPositions(); + m_vColumnTypes = aWizard.GetColumnTypes(); + m_bAppendFirstLine = !aWizard.UseHeaderLine(); + } + break; + default: + bError = true; // there is no error but I have nothing more to do + } + } + else + bError = true; + + if(!bError) + createRowSet(); + } + catch( const SQLException&) + { + ::dbtools::showError( ::dbtools::SQLExceptionInfo( ::cppu::getCaughtException() ), aWizard.getDialog()->GetXWindow(), m_xContext ); + bError = true; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + return bError; +} + +void ODatabaseExport::showErrorDialog(const css::sdbc::SQLException& e) +{ + if(!m_bDontAskAgain) + { + OUString aMsg = e.Message + + "\n" + + DBA_RES( STR_QRY_CONTINUE ); + OSQLWarningBox aBox(nullptr, aMsg, MessBoxStyle::YesNo | MessBoxStyle::DefaultNo); + + if (aBox.run() == RET_YES) + m_bDontAskAgain = true; + else + m_bError = true; + } +} + +void ODatabaseExport::adjustFormat() +{ + if ( m_sTextToken.isEmpty() ) + return; + + sal_Int32 nNewPos = m_bIsAutoIncrement ? m_nColumnPos+1 : m_nColumnPos; + OSL_ENSURE(nNewPos < static_cast<sal_Int32>(m_vColumnPositions.size()),"Illegal index for vector"); + if ( nNewPos < static_cast<sal_Int32>(m_vColumnPositions.size()) ) + { + sal_Int32 nColPos = m_vColumnPositions[nNewPos].first; + if( nColPos != COLUMN_POSITION_NOT_FOUND) + { + --nColPos; + OSL_ENSURE((nColPos) < static_cast<sal_Int32>(m_vNumberFormat.size()),"m_vFormatKey: Illegal index for vector"); + OSL_ENSURE((nColPos) < static_cast<sal_Int32>(m_vColumnSize.size()),"m_vColumnSize: Illegal index for vector"); + m_vNumberFormat[nColPos] = CheckString(m_sTextToken,m_vNumberFormat[nColPos]); + m_vColumnSize[nColPos] = std::max<sal_Int32>(static_cast<sal_Int32>(m_vColumnSize[nColPos]), m_sTextToken.getLength()); + } + } + eraseTokens(); +} + +void ODatabaseExport::eraseTokens() +{ + m_sTextToken.clear(); + m_sNumToken.clear(); +} + +void ODatabaseExport::ensureFormatter() +{ + if ( !m_pFormatter ) + { + Reference< XNumberFormatsSupplier > xSupplier = m_xFormatter->getNumberFormatsSupplier(); + auto pSupplierImpl = comphelper::getFromUnoTunnel<SvNumberFormatsSupplierObj>(xSupplier); + m_pFormatter = pSupplierImpl ? pSupplierImpl->GetNumberFormatter() : nullptr; + Reference<XPropertySet> xNumberFormatSettings = xSupplier->getNumberFormatSettings(); + xNumberFormatSettings->getPropertyValue("NullDate") >>= m_aNullDate; + } +} + +Reference< XPreparedStatement > ODatabaseExport::createPreparedStatment( const Reference<XDatabaseMetaData>& _xMetaData + ,const Reference<XPropertySet>& _xDestTable + ,const TPositions& _rvColumns) +{ + OUString sComposedTableName = ::dbtools::composeTableName( _xMetaData, _xDestTable, ::dbtools::EComposeRule::InDataManipulation, true ); + + OUStringBuffer aSql = "INSERT INTO " + + sComposedTableName + + " ( "; + + // set values and column names + OUStringBuffer aValues(" VALUES ( "); + + OUString aQuote; + if ( _xMetaData.is() ) + aQuote = _xMetaData->getIdentifierQuoteString(); + + Reference<XColumnsSupplier> xDestColsSup(_xDestTable,UNO_QUERY_THROW); + + // create sql string and set column types + Sequence< OUString> aDestColumnNames = xDestColsSup->getColumns()->getElementNames(); + if ( !aDestColumnNames.hasElements() ) + { + return Reference< XPreparedStatement > (); + } + const OUString* pIter = aDestColumnNames.getConstArray(); + std::vector< OUString> aInsertList; + aInsertList.resize(aDestColumnNames.getLength()+1); + for(size_t j=0; j < aInsertList.size(); ++j) + { + ODatabaseExport::TPositions::const_iterator aFind = std::find_if(_rvColumns.begin(),_rvColumns.end(), + [j] (const ODatabaseExport::TPositions::value_type& tPos) + { return tPos.second == static_cast<sal_Int32>(j+1); }); + if ( _rvColumns.end() != aFind && aFind->second != COLUMN_POSITION_NOT_FOUND && aFind->first != COLUMN_POSITION_NOT_FOUND ) + { + OSL_ENSURE((aFind->first) < static_cast<sal_Int32>(aInsertList.size()),"aInsertList: Illegal index for vector"); + aInsertList[aFind->first] = ::dbtools::quoteName( aQuote,*(pIter+j)); + } + } + + // create the sql string + for (auto const& elem : aInsertList) + { + if ( !elem.isEmpty() ) + { + aSql.append(elem); + aSql.append(","); + aValues.append("?,"); + } + } + + aSql[aSql.getLength()-1] = ')'; + aValues[aValues.getLength()-1] = ')'; + + aSql.append(aValues); + // now create,fill and execute the prepared statement + return _xMetaData->getConnection()->prepareStatement(aSql.makeStringAndClear()); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/misc/HtmlReader.cxx b/dbaccess/source/ui/misc/HtmlReader.cxx new file mode 100644 index 000000000..c2917a630 --- /dev/null +++ b/dbaccess/source/ui/misc/HtmlReader.cxx @@ -0,0 +1,481 @@ +/* -*- 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 <HtmlReader.hxx> +#include <connectivity/dbtools.hxx> +#include <toolkit/helper/vclunohelper.hxx> +#include <tools/stream.hxx> +#include <tools/tenccvt.hxx> +#include <comphelper/string.hxx> +#include <strings.hrc> +#include <osl/diagnose.h> +#include <core_resource.hxx> +#include <com/sun/star/sdbcx/XColumnsSupplier.hpp> +#include <com/sun/star/awt/FontWeight.hpp> +#include <com/sun/star/awt/FontStrikeout.hpp> +#include <com/sun/star/awt/FontSlant.hpp> +#include <com/sun/star/awt/FontUnderline.hpp> +#include <svtools/htmltokn.h> +#include <svtools/htmlkywd.hxx> +#include <tools/color.hxx> +#include <WExtendPages.hxx> +#include <vcl/svapp.hxx> +#include <vcl/settings.hxx> + +using namespace dbaui; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::awt; + +#define DBAUI_HTML_FONTSIZES 8 // like export, HTML-Options + +// OHTMLReader +OHTMLReader::OHTMLReader(SvStream& rIn,const SharedConnection& _rxConnection, + const Reference< css::util::XNumberFormatter >& _rxNumberF, + const css::uno::Reference< css::uno::XComponentContext >& _rxContext) + : HTMLParser(rIn) + , ODatabaseExport( _rxConnection, _rxNumberF, _rxContext, rIn ) + , m_nTableCount(0) + , m_nColumnWidth(87) +{ + SetSrcEncoding( GetExtendedCompatibilityTextEncoding( RTL_TEXTENCODING_ISO_8859_1 ) ); + // If the file starts with a BOM, switch to UCS2. + SetSwitchToUCS2( true ); +} + +OHTMLReader::OHTMLReader(SvStream& rIn, + sal_Int32 nRows, + TPositions&& _rColumnPositions, + const Reference< css::util::XNumberFormatter >& _rxNumberF, + const css::uno::Reference< css::uno::XComponentContext >& _rxContext, + const TColumnVector* pList, + const OTypeInfoMap* _pInfoMap, + bool _bAutoIncrementEnabled) + : HTMLParser(rIn) + , ODatabaseExport( nRows, std::move(_rColumnPositions), _rxNumberF, _rxContext, pList, _pInfoMap, _bAutoIncrementEnabled, rIn ) + , m_nTableCount(0) + , m_nColumnWidth(87) +{ + SetSrcEncoding( GetExtendedCompatibilityTextEncoding( RTL_TEXTENCODING_ISO_8859_1 ) ); + // If the file starts with a BOM, switch to UCS2. + SetSwitchToUCS2( true ); +} + +OHTMLReader::~OHTMLReader() +{ +} + +SvParserState OHTMLReader::CallParser() +{ + rInput.Seek(STREAM_SEEK_TO_BEGIN); + rInput.ResetError(); + SvParserState eParseState = HTMLParser::CallParser(); + SetColumnTypes(m_pColumnList,m_pInfoMap); + return m_bFoundTable ? eParseState : SvParserState::Error; +} + +#if defined _MSC_VER +#pragma warning(disable: 4702) // unreachable code, bug in MSVC2015 +#endif +void OHTMLReader::NextToken( HtmlTokenId nToken ) +{ + if(m_bError || !m_nRows) // if there is an error or no more rows to check, return immediately + return; + if ( nToken == HtmlTokenId::META ) + setTextEncoding(); + + if(m_xConnection.is()) // names, which CTOR was called and hence, if a table should be created + { + switch(nToken) + { + case HtmlTokenId::TABLE_ON: + ++m_nTableCount; + { // can also be TD or TH, if there was no TABLE before + const HTMLOptions& rHtmlOptions = GetOptions(); + for (const auto & rOption : rHtmlOptions) + { + if( rOption.GetToken() == HtmlOptionId::WIDTH ) + { // percentage: of document width respectively outer cell + m_nColumnWidth = GetWidthPixel( rOption ); + } + } + } + [[fallthrough]]; + case HtmlTokenId::THEAD_ON: + case HtmlTokenId::TBODY_ON: + { + sal_uInt64 const nTell = rInput.Tell(); // perhaps alters position of the stream + if ( !m_xTable.is() ) + {// use first line as header + m_bError = !CreateTable(nToken); + if ( m_bAppendFirstLine ) + rInput.Seek(nTell); + } + } + break; + case HtmlTokenId::TABLE_OFF: + if(!--m_nTableCount) + { + m_xTable = nullptr; + } + break; + case HtmlTokenId::TABLEROW_ON: + if ( !m_pUpdateHelper ) + m_bError = true; + break; + case HtmlTokenId::TEXTTOKEN: + case HtmlTokenId::SINGLECHAR: + if ( m_bInTbl ) //&& !m_bSDNum ) // important, as otherwise we also get the names of the fonts + m_sTextToken += aToken; + break; + case HtmlTokenId::PARABREAK_OFF: + m_sCurrent += m_sTextToken; + break; + case HtmlTokenId::PARABREAK_ON: + m_sTextToken.clear(); + break; + case HtmlTokenId::TABLEDATA_ON: + fetchOptions(); + break; + case HtmlTokenId::TABLEDATA_OFF: + { + if ( !m_sCurrent.isEmpty() ) + m_sTextToken = m_sCurrent; + try + { + insertValueIntoColumn(); + } + catch(SQLException& e) + // handling update failure + { + showErrorDialog(e); + } + m_sCurrent.clear(); + m_nColumnPos++; + eraseTokens(); + m_bInTbl = false; + } + break; + case HtmlTokenId::TABLEROW_OFF: + if ( !m_pUpdateHelper ) + { + m_bError = true; + break; + } + try + { + m_nRowCount++; + if (m_bIsAutoIncrement) // if bSetAutoIncrement then I have to set the autoincrement + m_pUpdateHelper->updateInt(1,m_nRowCount); + m_pUpdateHelper->insertRow(); + } + catch(SQLException& e) + // handling update failure + { + showErrorDialog(e); + } + m_nColumnPos = 0; + break; + default: break; + } + } + else // branch only valid for type checking + { + switch(nToken) + { + case HtmlTokenId::THEAD_ON: + case HtmlTokenId::TBODY_ON: + // The head of the column is not included + if(m_bHead) + { + do + {} + while(GetNextToken() != HtmlTokenId::TABLEROW_OFF); + m_bHead = false; + } + break; + case HtmlTokenId::TABLEDATA_ON: + case HtmlTokenId::TABLEHEADER_ON: + fetchOptions(); + break; + case HtmlTokenId::TEXTTOKEN: + case HtmlTokenId::SINGLECHAR: + if ( m_bInTbl ) // && !m_bSDNum ) // important, as otherwise we also get the names of the fonts + m_sTextToken += aToken; + break; + case HtmlTokenId::PARABREAK_OFF: + m_sCurrent += m_sTextToken; + break; + case HtmlTokenId::PARABREAK_ON: + m_sTextToken.clear(); + break; + case HtmlTokenId::TABLEDATA_OFF: + if ( !m_sCurrent.isEmpty() ) + m_sTextToken = m_sCurrent; + adjustFormat(); + m_nColumnPos++; + m_bInTbl = false; + m_sCurrent.clear(); + break; + case HtmlTokenId::TABLEROW_OFF: + if ( !m_sCurrent.isEmpty() ) + m_sTextToken = m_sCurrent; + adjustFormat(); + m_nColumnPos = 0; + m_nRows--; + m_sCurrent.clear(); + break; + default: break; + } + } +} + +void OHTMLReader::fetchOptions() +{ + m_bInTbl = true; + const HTMLOptions& options = GetOptions(); + for (const auto & rOption : options) + { + switch( rOption.GetToken() ) + { + case HtmlOptionId::SDNUM: + m_sNumToken = rOption.GetString(); + break; + default: break; + } + } +} + +void OHTMLReader::TableDataOn(SvxCellHorJustify& eVal) +{ + const HTMLOptions& rHtmlOptions = GetOptions(); + for (const auto & rOption : rHtmlOptions) + { + switch( rOption.GetToken() ) + { + case HtmlOptionId::ALIGN: + { + const OUString& rOptVal = rOption.GetString(); + if (rOptVal.equalsIgnoreAsciiCase( OOO_STRING_SVTOOLS_HTML_AL_right )) + eVal = SvxCellHorJustify::Right; + else if (rOptVal.equalsIgnoreAsciiCase( OOO_STRING_SVTOOLS_HTML_AL_center )) + eVal = SvxCellHorJustify::Center; + else if (rOptVal.equalsIgnoreAsciiCase( OOO_STRING_SVTOOLS_HTML_AL_left )) + eVal = SvxCellHorJustify::Left; + else + eVal = SvxCellHorJustify::Standard; + } + break; + default: break; + } + } +} + +void OHTMLReader::TableFontOn(FontDescriptor& _rFont, Color &_rTextColor) +{ + const HTMLOptions& rHtmlOptions = GetOptions(); + for (const auto & rOption : rHtmlOptions) + { + switch( rOption.GetToken() ) + { + case HtmlOptionId::COLOR: + { + Color aColor; + rOption.GetColor( aColor ); + _rTextColor = aColor.GetRGBColor(); + } + break; + case HtmlOptionId::FACE : + { + const OUString& rFace = rOption.GetString(); + OUStringBuffer aFontName; + sal_Int32 nPos = 0; + while( nPos != -1 ) + { + // list of fonts, VCL: semicolon as separator, HTML: comma + std::u16string_view aFName = o3tl::getToken(rFace, 0, ',', nPos ); + aFName = comphelper::string::strip(aFName, ' '); + if( !aFontName.isEmpty() ) + aFontName.append(";"); + aFontName.append(aFName); + } + if ( !aFontName.isEmpty() ) + _rFont.Name = aFontName.makeStringAndClear(); + } + break; + case HtmlOptionId::SIZE : + { + sal_Int16 nSize = static_cast<sal_Int16>(rOption.GetNumber()); + if ( nSize == 0 ) + nSize = 1; + else if ( nSize < DBAUI_HTML_FONTSIZES ) + nSize = DBAUI_HTML_FONTSIZES; + + _rFont.Height = nSize; + } + break; + default: break; + } + } +} + +sal_Int16 OHTMLReader::GetWidthPixel( const HTMLOption& rOption ) +{ + const OUString& rOptVal = rOption.GetString(); + if ( rOptVal.indexOf('%') != -1 ) + { // percentage + OSL_ENSURE( m_nColumnWidth, "WIDTH Option: m_nColumnWidth==0 and Width%" ); + return static_cast<sal_Int16>((rOption.GetNumber() * m_nColumnWidth) / 100); + } + else + { + if ( rOptVal.indexOf('*') != -1 ) + { // relative to what?!? +//TODO: collect ColArray of all relevant values and then MakeCol + return 0; + } + else + return static_cast<sal_Int16>(rOption.GetNumber()); // pixel + } +} + +bool OHTMLReader::CreateTable(HtmlTokenId nToken) +{ + OUString aTempName(DBA_RES(STR_TBL_TITLE)); + aTempName = aTempName.getToken(0,' '); + aTempName = ::dbtools::createUniqueName(m_xTables, aTempName); + + bool bCaption = false; + bool bTableHeader = false; + OUString aColumnName; + SvxCellHorJustify eVal; + + OUString aTableName; + FontDescriptor aFont = VCLUnoHelper::CreateFontDescriptor(Application::GetSettings().GetStyleSettings().GetAppFont()); + Color nTextColor; + do + { + switch (nToken) + { + case HtmlTokenId::TEXTTOKEN: + case HtmlTokenId::SINGLECHAR: + if(bTableHeader) + aColumnName += aToken; + if(bCaption) + aTableName += aToken; + break; + case HtmlTokenId::PARABREAK_OFF: + m_sCurrent += aColumnName; + break; + case HtmlTokenId::PARABREAK_ON: + m_sTextToken.clear(); + break; + case HtmlTokenId::TABLEDATA_ON: + case HtmlTokenId::TABLEHEADER_ON: + TableDataOn(eVal); + bTableHeader = true; + break; + case HtmlTokenId::TABLEDATA_OFF: + case HtmlTokenId::TABLEHEADER_OFF: + { + aColumnName = comphelper::string::strip(aColumnName, ' ' ); + if (aColumnName.isEmpty() || m_bAppendFirstLine ) + aColumnName = DBA_RES(STR_COLUMN_NAME); + else if ( !m_sCurrent.isEmpty() ) + aColumnName = m_sCurrent; + + aColumnName = comphelper::string::strip(aColumnName, ' '); + CreateDefaultColumn(aColumnName); + aColumnName.clear(); + m_sCurrent.clear(); + + eVal = SvxCellHorJustify::Standard; + bTableHeader = false; + } + break; + + case HtmlTokenId::TITLE_ON: + case HtmlTokenId::CAPTION_ON: + bCaption = true; + break; + case HtmlTokenId::TITLE_OFF: + case HtmlTokenId::CAPTION_OFF: + aTableName = comphelper::string::strip(aTableName, ' '); + if(aTableName.isEmpty()) + aTableName = ::dbtools::createUniqueName(m_xTables, aTableName); + else + aTableName = aTempName; + bCaption = false; + break; + case HtmlTokenId::FONT_ON: + TableFontOn(aFont,nTextColor); + break; + case HtmlTokenId::BOLD_ON: + aFont.Weight = css::awt::FontWeight::BOLD; + break; + case HtmlTokenId::ITALIC_ON: + aFont.Slant = css::awt::FontSlant_ITALIC; + break; + case HtmlTokenId::UNDERLINE_ON: + aFont.Underline = css::awt::FontUnderline::SINGLE; + break; + case HtmlTokenId::STRIKE_ON: + aFont.Strikeout = css::awt::FontStrikeout::SINGLE; + break; + default: break; + } + nToken = GetNextToken(); + } + while (nToken != HtmlTokenId::TABLEROW_OFF); + + if ( !m_sCurrent.isEmpty() ) + aColumnName = m_sCurrent; + aColumnName = comphelper::string::strip(aColumnName, ' '); + if(!aColumnName.isEmpty()) + CreateDefaultColumn(aColumnName); + + if ( m_vDestVector.empty() ) + return false; + + if(aTableName.isEmpty()) + aTableName = aTempName; + + m_bInTbl = false; + m_bFoundTable = true; + + if ( isCheckEnabled() ) + return true; + + return !executeWizard(aTableName,Any(nTextColor),aFont) && m_xTable.is(); +} + +void OHTMLReader::setTextEncoding() +{ + ParseMetaOptions(nullptr, nullptr); +} + +TypeSelectionPageFactory OHTMLReader::getTypeSelectionPageFactory() +{ + return &OWizHTMLExtend::Create; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/misc/RowSetDrop.cxx b/dbaccess/source/ui/misc/RowSetDrop.cxx new file mode 100644 index 000000000..065fee9ce --- /dev/null +++ b/dbaccess/source/ui/misc/RowSetDrop.cxx @@ -0,0 +1,247 @@ + +/* -*- 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 <DExport.hxx> +#include <TokenWriter.hxx> +#include <com/sun/star/sdbc/XColumnLocate.hpp> +#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp> +#include <sal/log.hxx> +#include <osl/diagnose.h> +#include <core_resource.hxx> +#include <strings.hrc> +#include <strings.hxx> +#include <sqlmessage.hxx> +#include <com/sun/star/sdbc/XRowUpdate.hpp> + +using namespace dbaui; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::sdb; +using namespace ::com::sun::star::lang; + +// export data +ORowSetImportExport::ORowSetImportExport(weld::Window* pParent, + const Reference< XResultSetUpdate >& xResultSetUpdate, + const svx::ODataAccessDescriptor& aDataDescriptor, + const Reference< XComponentContext >& rM) + : ODatabaseImportExport(aDataDescriptor,rM,nullptr) + ,m_xTargetResultSetUpdate(xResultSetUpdate) + ,m_xTargetRowUpdate(xResultSetUpdate,UNO_QUERY) + ,m_pParent(pParent) + ,m_bAlreadyAsked(false) +{ + OSL_ENSURE(pParent,"Window can't be null!"); +} + +void ORowSetImportExport::initialize() +{ + ODatabaseImportExport::initialize(); + // do namemapping + Reference<XColumnLocate> xColumnLocate(m_xResultSet,UNO_QUERY); + OSL_ENSURE(xColumnLocate.is(),"The rowset normally should support this"); + + m_xTargetResultSetMetaData = Reference<XResultSetMetaDataSupplier>(m_xTargetResultSetUpdate,UNO_QUERY_THROW)->getMetaData(); + if(!m_xTargetResultSetMetaData.is() || !xColumnLocate.is() || !m_xResultSetMetaData.is() ) + throw SQLException(DBA_RES(STR_UNEXPECTED_ERROR),*this,"S1000",0,Any()); + + sal_Int32 nCount = m_xTargetResultSetMetaData->getColumnCount(); + m_aColumnMapping.reserve(nCount); + m_aColumnTypes.reserve(nCount); + for (sal_Int32 i = 1;i <= nCount; ++i) + { + sal_Int32 nPos = COLUMN_POSITION_NOT_FOUND; // means column is autoincrement or doesn't exist + if(!m_xTargetResultSetMetaData->isAutoIncrement(i)) + { + try + { + OUString sColumnName = m_xTargetResultSetMetaData->getColumnName(i); + nPos = xColumnLocate->findColumn(sColumnName); + } + catch(const SQLException&) + { + if(m_xTargetResultSetMetaData->isNullable(i)) + nPos = 0; // column doesn't exist but we could set it to null + } + } + + m_aColumnMapping.push_back(nPos); + if(nPos > 0) + m_aColumnTypes.push_back(m_xResultSetMetaData->getColumnType(nPos)); + else + m_aColumnTypes.push_back(DataType::OTHER); + } +} + +bool ORowSetImportExport::Write() +{ + return true; +} + +bool ORowSetImportExport::Read() +{ + // check if there is any column to copy + if(std::none_of(m_aColumnMapping.begin(),m_aColumnMapping.end(), + [](sal_Int32 n) { return n > 0; })) + return false; + bool bContinue = true; + if(m_aSelection.hasElements()) + { + const Any* pBegin = m_aSelection.getConstArray(); + const Any* pEnd = pBegin + m_aSelection.getLength(); + for(;pBegin != pEnd && bContinue;++pBegin) + { + sal_Int32 nPos = -1; + *pBegin >>= nPos; + OSL_ENSURE(nPos != -1,"Invalid position!"); + bContinue = (m_xResultSet.is() && m_xResultSet->absolute(nPos) && insertNewRow()); + } + } + else + { + Reference<XPropertySet> xProp(m_xResultSet,UNO_QUERY); + sal_Int32 nRowCount = 0; + if ( xProp.is() && xProp->getPropertySetInfo()->hasPropertyByName(PROPERTY_ISROWCOUNTFINAL) ) + { + bool bFinal = false; + xProp->getPropertyValue(PROPERTY_ISROWCOUNTFINAL) >>= bFinal; + if ( !bFinal ) + m_xResultSet->afterLast(); + xProp->getPropertyValue(PROPERTY_ROWCOUNT) >>= nRowCount; + } + if ( !nRowCount ) + { + m_xResultSet->afterLast(); + nRowCount = m_xResultSet->getRow(); + } + OSL_ENSURE(nRowCount,"RowCount is 0!"); + m_xResultSet->beforeFirst(); + while(m_xResultSet.is() && m_xResultSet->next() && bContinue && nRowCount ) + { + --nRowCount; + bContinue = insertNewRow(); + } + } + return true; +} + +bool ORowSetImportExport::insertNewRow() +{ + try + { + m_xTargetResultSetUpdate->moveToInsertRow(); + sal_Int32 i = 1; + for (auto const& column : m_aColumnMapping) + { + if(column > 0) + { + Any aValue; + switch(m_aColumnTypes[i-1]) + { + case DataType::CHAR: + case DataType::VARCHAR: + aValue <<= m_xRow->getString(column); + break; + case DataType::DECIMAL: + case DataType::NUMERIC: + aValue <<= m_xRow->getDouble(column); + break; + case DataType::BIGINT: + aValue <<= m_xRow->getLong(column); + break; + case DataType::FLOAT: + aValue <<= m_xRow->getFloat(column); + break; + case DataType::DOUBLE: + aValue <<= m_xRow->getDouble(column); + break; + case DataType::LONGVARCHAR: + aValue <<= m_xRow->getString(column); + break; + case DataType::LONGVARBINARY: + aValue <<= m_xRow->getBytes(column); + break; + case DataType::DATE: + aValue <<= m_xRow->getDate(column); + break; + case DataType::TIME: + aValue <<= m_xRow->getTime(column); + break; + case DataType::TIMESTAMP: + aValue <<= m_xRow->getTimestamp(column); + break; + case DataType::BIT: + case DataType::BOOLEAN: + aValue <<= m_xRow->getBoolean(column); + break; + case DataType::TINYINT: + aValue <<= m_xRow->getByte(column); + break; + case DataType::SMALLINT: + aValue <<= m_xRow->getShort(column); + break; + case DataType::INTEGER: + aValue <<= m_xRow->getInt(column); + break; + case DataType::REAL: + aValue <<= m_xRow->getDouble(column); + break; + case DataType::BINARY: + case DataType::VARBINARY: + aValue <<= m_xRow->getBytes(column); + break; + case DataType::BLOB: + aValue <<= m_xRow->getBlob(column); + break; + case DataType::CLOB: + aValue <<= m_xRow->getClob(column); + break; + default: + SAL_WARN("dbaccess.ui", "Unknown type"); + } + if(m_xRow->wasNull()) + m_xTargetRowUpdate->updateNull(i); + else + m_xTargetRowUpdate->updateObject(i,aValue); + } + else if(column == 0)//now we have know that we to set this column to null + m_xTargetRowUpdate->updateNull(i); + ++i; + } + m_xTargetResultSetUpdate->insertRow(); + } + catch(const SQLException&) + { + if(!m_bAlreadyAsked) + { + OUString sAskIfContinue = DBA_RES(STR_ERROR_OCCURRED_WHILE_COPYING); + OSQLWarningBox aDlg(m_pParent, sAskIfContinue, MessBoxStyle::YesNo | MessBoxStyle::DefaultYes); + if (aDlg.run() == RET_YES) + m_bAlreadyAsked = true; + else + return false; + } + } + return true; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/misc/RtfReader.cxx b/dbaccess/source/ui/misc/RtfReader.cxx new file mode 100644 index 000000000..8895d494f --- /dev/null +++ b/dbaccess/source/ui/misc/RtfReader.cxx @@ -0,0 +1,309 @@ +/* -*- 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 <RtfReader.hxx> +#include <tools/stream.hxx> +#include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp> +#include <com/sun/star/awt/FontDescriptor.hpp> +#include <com/sun/star/awt/FontWeight.hpp> +#include <com/sun/star/awt/FontStrikeout.hpp> +#include <com/sun/star/awt/FontSlant.hpp> +#include <com/sun/star/awt/FontUnderline.hpp> +#include <core_resource.hxx> +#include <svtools/rtftoken.h> +#include <toolkit/helper/vclunohelper.hxx> +#include <strings.hrc> +#include <connectivity/dbtools.hxx> +#include <comphelper/string.hxx> +#include <tools/color.hxx> +#include <WExtendPages.hxx> +#include <vcl/svapp.hxx> +#include <vcl/settings.hxx> + +using namespace dbaui; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::awt; + +// ORTFReader +ORTFReader::ORTFReader( SvStream& rIn, + const SharedConnection& _rxConnection, + const Reference< css::util::XNumberFormatter >& _rxNumberF, + const css::uno::Reference< css::uno::XComponentContext >& _rxContext) + :SvRTFParser(rIn) + ,ODatabaseExport( _rxConnection, _rxNumberF, _rxContext, rIn ) +{ + m_bAppendFirstLine = false; +} + +ORTFReader::ORTFReader(SvStream& rIn, + sal_Int32 nRows, + TPositions&& _rColumnPositions, + const Reference< css::util::XNumberFormatter >& _rxNumberF, + const css::uno::Reference< css::uno::XComponentContext >& _rxContext, + const TColumnVector* pList, + const OTypeInfoMap* _pInfoMap, + bool _bAutoIncrementEnabled) + :SvRTFParser(rIn) + ,ODatabaseExport( nRows, std::move(_rColumnPositions), _rxNumberF, _rxContext, pList, _pInfoMap, _bAutoIncrementEnabled, rIn ) +{ + m_bAppendFirstLine = false; +} + +ORTFReader::~ORTFReader() +{ +} + +SvParserState ORTFReader::CallParser() +{ + rInput.Seek(STREAM_SEEK_TO_BEGIN); + rInput.ResetError(); + SvParserState eParseState = SvRTFParser::CallParser(); + SetColumnTypes(m_pColumnList,m_pInfoMap); + return m_bFoundTable ? eParseState : SvParserState::Error; +} + +#if defined _MSC_VER +#pragma warning(disable: 4702) // unreachable code, bug in MSVC2015 +#endif + +void ORTFReader::NextToken( int nToken ) +{ + if(m_bError || !m_nRows) // if there is an error or no more rows to check, return immediately + return; + + if(m_xConnection.is()) // names, which CTOR was called and hence, if a table should be created + { + switch(nToken) + { + case RTF_COLORTBL: + { + + int nTmpToken2 = GetNextToken(); + do + { + Color aColor; + do + { + switch(nTmpToken2) + { + case RTF_RED: aColor.SetRed(static_cast<sal_uInt8>(nTokenValue)); break; + case RTF_BLUE: aColor.SetBlue(static_cast<sal_uInt8>(nTokenValue)); break; + case RTF_GREEN: aColor.SetGreen(static_cast<sal_uInt8>(nTokenValue)); break; + default: break; + } + nTmpToken2 = GetNextToken(); + } + while(aToken[0] != ';' && eState != SvParserState::Error && eState != SvParserState::Accepted); + m_vecColor.push_back(aColor.GetRGBColor()); + nTmpToken2 = GetNextToken(); + } + while(nTmpToken2 == RTF_RED && eState != SvParserState::Error && eState != SvParserState::Accepted); + SkipToken(); + } + break; + + case RTF_TROWD: + { + if ( !m_xTable.is() ) // use first line as header + { + sal_uInt64 const nTell = rInput.Tell(); // perhaps alters position of the stream + + m_bError = !CreateTable(nToken); + if ( m_bAppendFirstLine ) + { + rInput.Seek(nTell); + rInput.ResetError(); + } + } + } + break; + case RTF_INTBL: + if(m_bInTbl) + { + eraseTokens(); + } + + m_bInTbl = true; // Now we are in a table description + break; + case RTF_TEXTTOKEN: + case RTF_SINGLECHAR: + if(m_bInTbl) // important, as otherwise we also get the names of the fonts + m_sTextToken += aToken; + break; + case RTF_CELL: + { + try + { + insertValueIntoColumn(); + } + catch(SQLException& e) + // handling update failure + { + showErrorDialog(e); + } + m_nColumnPos++; + eraseTokens(); + } + break; + case RTF_ROW: + // it can happen that the last cell is not concluded with \cell + try + { + insertValueIntoColumn(); + m_nRowCount++; + if(m_bIsAutoIncrement) // if bSetAutoIncrement then I have to set the autoincrement + m_pUpdateHelper->updateInt(1,m_nRowCount); + m_pUpdateHelper->insertRow(); + } + catch(SQLException& e) + // handling update failure + { + showErrorDialog(e); + } + m_nColumnPos = 0; + break; + } + } + else // branch only valid for type checking + { + switch(nToken) + { + case RTF_TROWD: + // The head of the column is not included + if(m_bHead) + { + do + {} + while(GetNextToken() != RTF_ROW && eState != SvParserState::Error && eState != SvParserState::Accepted); + m_bHead = false; + } + break; + case RTF_INTBL: + m_bInTbl = true; + break; + case RTF_TEXTTOKEN: + case RTF_SINGLECHAR: + if(m_bInTbl) + m_sTextToken += aToken; + break; + case RTF_CELL: + adjustFormat(); + m_nColumnPos++; + break; + case RTF_ROW: + adjustFormat(); + m_nColumnPos = 0; + m_nRows--; + break; + } + } +} + +bool ORTFReader::CreateTable(int nToken) +{ + OUString aTableName(DBA_RES(STR_TBL_TITLE)); + aTableName = aTableName.getToken(0,' '); + aTableName = ::dbtools::createUniqueName(m_xTables, aTableName); + + OUString aColumnName; + + FontDescriptor aFont = VCLUnoHelper::CreateFontDescriptor(Application::GetSettings().GetStyleSettings().GetAppFont()); + do + { + switch (nToken) + { + case RTF_UNKNOWNCONTROL: + case RTF_UNKNOWNDATA: + m_bInTbl = false; + aColumnName.clear(); + break; + case RTF_INTBL: + if(m_bInTbl) + aColumnName.clear(); + + m_bInTbl = true; + break; + case RTF_TEXTTOKEN: + case RTF_SINGLECHAR: + if(m_bInTbl) + aColumnName += aToken; + break; + case RTF_CELL: + { + aColumnName = comphelper::string::strip(aColumnName, ' '); + if (aColumnName.isEmpty() || m_bAppendFirstLine ) + aColumnName = DBA_RES(STR_COLUMN_NAME); + + CreateDefaultColumn(aColumnName); + aColumnName.clear(); + } + break; + case RTF_CF: + break; + case RTF_B: + aFont.Weight = css::awt::FontWeight::BOLD; + break; + case RTF_I: + aFont.Slant = css::awt::FontSlant_ITALIC; + break; + case RTF_UL: + aFont.Underline = css::awt::FontUnderline::SINGLE; + break; + case RTF_STRIKE: + aFont.Strikeout = css::awt::FontStrikeout::SINGLE; + break; + } + nToken = GetNextToken(); + } + while(nToken != RTF_TROWD && eState != SvParserState::Error && eState != SvParserState::Accepted); + + bool bOk = !m_vDestVector.empty(); + if(bOk) + { + if ( !aColumnName.isEmpty() ) + { + if ( m_bAppendFirstLine ) + aColumnName = DBA_RES(STR_COLUMN_NAME); + CreateDefaultColumn(aColumnName); + } + + m_bInTbl = false; + m_bFoundTable = true; + + if ( isCheckEnabled() ) + return true; + Any aTextColor; + if(!m_vecColor.empty()) + aTextColor <<= m_vecColor[0]; + + bOk = !executeWizard(aTableName,aTextColor,aFont) && m_xTable.is(); + } + return bOk; +} + +TypeSelectionPageFactory ORTFReader::getTypeSelectionPageFactory() +{ + return &OWizRTFExtend::Create; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/misc/TableCopyHelper.cxx b/dbaccess/source/ui/misc/TableCopyHelper.cxx new file mode 100644 index 000000000..c855b3b48 --- /dev/null +++ b/dbaccess/source/ui/misc/TableCopyHelper.cxx @@ -0,0 +1,306 @@ +/* -*- 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 <TableCopyHelper.hxx> +#include <core_resource.hxx> +#include <strings.hrc> +#include <strings.hxx> +#include <dbaccess/genericcontroller.hxx> +#include <com/sun/star/task/InteractionHandler.hpp> +#include <com/sun/star/task/XInteractionHandler.hpp> +#include <com/sun/star/sdb/application/CopyTableOperation.hpp> +#include <com/sun/star/sdb/application/CopyTableWizard.hpp> +#include <com/sun/star/sdb/DataAccessDescriptorFactory.hpp> +#include <com/sun/star/sdb/CommandType.hpp> + +#include <TokenWriter.hxx> +#include <UITools.hxx> +#include <dbaccess/dataview.hxx> +#include <svx/dbaexchange.hxx> +#include <unotools/ucbhelper.hxx> +#include <tools/urlobj.hxx> +#include <tools/diagnose_ex.h> +#include <sal/log.hxx> +#include <toolkit/helper/vclunohelper.hxx> +#include <unotools/tempfile.hxx> +#include <cppuhelper/exc_hlp.hxx> + +namespace dbaui +{ +using namespace ::dbtools; +using namespace ::svx; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::task; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::sdb; +using namespace ::com::sun::star::sdb::application; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::ucb; + +OTableCopyHelper::OTableCopyHelper(OGenericUnoController* _pController) + :m_pController(_pController) +{ +} + +void OTableCopyHelper::insertTable( std::u16string_view i_rSourceDataSource, const Reference<XConnection>& i_rSourceConnection, + const OUString& i_rCommand, const sal_Int32 i_nCommandType, + const Reference< XResultSet >& i_rSourceRows, const Sequence< Any >& i_rSelection, const bool i_bBookmarkSelection, + std::u16string_view i_rDestDataSource, const Reference<XConnection>& i_rDestConnection) +{ + if ( CommandType::QUERY != i_nCommandType && CommandType::TABLE != i_nCommandType ) + { + SAL_WARN("dbaccess.ui", "OTableCopyHelper::insertTable: invalid call (no supported format found)!" ); + return; + } + + try + { + Reference<XConnection> xSrcConnection( i_rSourceConnection ); + if ( i_rSourceDataSource == i_rDestDataSource ) + xSrcConnection = i_rDestConnection; + + if ( !xSrcConnection.is() || !i_rDestConnection.is() ) + { + SAL_WARN("dbaccess.ui", "OTableCopyHelper::insertTable: no connection/s!" ); + return; + } + + Reference<XComponentContext> aContext( m_pController->getORB() ); + + Reference< XDataAccessDescriptorFactory > xFactory( DataAccessDescriptorFactory::get( aContext ) ); + + Reference< XPropertySet > xSource( xFactory->createDataAccessDescriptor(), UNO_SET_THROW ); + xSource->setPropertyValue( PROPERTY_COMMAND_TYPE, Any( i_nCommandType ) ); + xSource->setPropertyValue( PROPERTY_COMMAND, Any( i_rCommand ) ); + xSource->setPropertyValue( PROPERTY_ACTIVE_CONNECTION, Any( xSrcConnection ) ); + xSource->setPropertyValue( PROPERTY_RESULT_SET, Any( i_rSourceRows ) ); + xSource->setPropertyValue( PROPERTY_SELECTION, Any( i_rSelection ) ); + xSource->setPropertyValue( PROPERTY_BOOKMARK_SELECTION, Any( i_bBookmarkSelection ) ); + + Reference< XPropertySet > xDest( xFactory->createDataAccessDescriptor(), UNO_SET_THROW ); + xDest->setPropertyValue( PROPERTY_ACTIVE_CONNECTION, Any( i_rDestConnection ) ); + + auto xInteractionHandler = InteractionHandler::createWithParent(aContext, VCLUnoHelper::GetInterface(m_pController->getView())); + + Reference<XCopyTableWizard> xWizard(CopyTableWizard::createWithInteractionHandler(aContext, xSource, xDest, xInteractionHandler), UNO_SET_THROW); + + OUString sTableNameForAppend( GetTableNameForAppend() ); + xWizard->setDestinationTableName( GetTableNameForAppend() ); + + bool bAppendToExisting = !sTableNameForAppend.isEmpty(); + xWizard->setOperation( bAppendToExisting ? CopyTableOperation::AppendData : CopyTableOperation::CopyDefinitionAndData ); + + xWizard->execute(); + } + catch( const SQLException& ) + { + m_pController->showError( SQLExceptionInfo( ::cppu::getCaughtException() ) ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +void OTableCopyHelper::pasteTable( const svx::ODataAccessDescriptor& _rPasteData, std::u16string_view i_rDestDataSourceName, + const SharedConnection& i_rDestConnection ) +{ + OUString sSrcDataSourceName = _rPasteData.getDataSource(); + + OUString sCommand; + _rPasteData[ DataAccessDescriptorProperty::Command ] >>= sCommand; + + Reference<XConnection> xSrcConnection; + if ( _rPasteData.has(DataAccessDescriptorProperty::Connection) ) + { + OSL_VERIFY( _rPasteData[DataAccessDescriptorProperty::Connection] >>= xSrcConnection ); + } + + Reference< XResultSet > xResultSet; + if ( _rPasteData.has(DataAccessDescriptorProperty::Cursor) ) + { + OSL_VERIFY( _rPasteData[ DataAccessDescriptorProperty::Cursor ] >>= xResultSet ); + } + + Sequence< Any > aSelection; + if ( _rPasteData.has( DataAccessDescriptorProperty::Selection ) ) + { + OSL_VERIFY( _rPasteData[ DataAccessDescriptorProperty::Selection ] >>= aSelection ); + OSL_ENSURE( _rPasteData.has( DataAccessDescriptorProperty::BookmarkSelection ), "OTableCopyHelper::pasteTable: you should specify BookmarkSelection, too, to be on the safe side!" ); + } + + bool bBookmarkSelection( true ); + if ( _rPasteData.has( DataAccessDescriptorProperty::BookmarkSelection ) ) + { + OSL_VERIFY( _rPasteData[ DataAccessDescriptorProperty::BookmarkSelection ] >>= bBookmarkSelection ); + } + OSL_ENSURE( bBookmarkSelection, "OTableCopyHelper::pasteTable: working with selection-indices (instead of bookmarks) is error-prone, and thus deprecated!" ); + + sal_Int32 nCommandType = CommandType::COMMAND; + if ( _rPasteData.has(DataAccessDescriptorProperty::CommandType) ) + _rPasteData[DataAccessDescriptorProperty::CommandType] >>= nCommandType; + + insertTable( sSrcDataSourceName, xSrcConnection, sCommand, nCommandType, + xResultSet, aSelection, bBookmarkSelection, + i_rDestDataSourceName, i_rDestConnection ); +} + +void OTableCopyHelper::pasteTable( SotClipboardFormatId _nFormatId + ,const TransferableDataHelper& _rTransData + ,std::u16string_view i_rDestDataSource + ,const SharedConnection& _xConnection) +{ + if ( _nFormatId == SotClipboardFormatId::DBACCESS_TABLE || _nFormatId == SotClipboardFormatId::DBACCESS_QUERY ) + { + if ( ODataAccessObjectTransferable::canExtractObjectDescriptor(_rTransData.GetDataFlavorExVector()) ) + { + svx::ODataAccessDescriptor aPasteData = ODataAccessObjectTransferable::extractObjectDescriptor(_rTransData); + pasteTable( aPasteData,i_rDestDataSource,_xConnection); + } + } + else if ( _rTransData.HasFormat(_nFormatId) ) + { + try + { + DropDescriptor aTrans; + bool bOk; + if ( _nFormatId != SotClipboardFormatId::RTF ) + bOk = _rTransData.GetSotStorageStream(SotClipboardFormatId::HTML ,aTrans.aHtmlRtfStorage); + else + bOk = _rTransData.GetSotStorageStream(SotClipboardFormatId::RTF,aTrans.aHtmlRtfStorage); + + aTrans.nType = E_TABLE; + aTrans.bHtml = SotClipboardFormatId::HTML == _nFormatId; + aTrans.sDefaultTableName = GetTableNameForAppend(); + if ( !bOk || !copyTagTable(aTrans,false,_xConnection) ) + m_pController->showError(SQLException(DBA_RES(STR_NO_TABLE_FORMAT_INSIDE), *m_pController, "S1000", 0, Any())); + } + catch(const SQLException&) + { + m_pController->showError( SQLExceptionInfo( ::cppu::getCaughtException() ) ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + else + m_pController->showError(SQLException(DBA_RES(STR_NO_TABLE_FORMAT_INSIDE), *m_pController, "S1000", 0, Any())); +} + +void OTableCopyHelper::pasteTable( const TransferableDataHelper& _rTransData + ,std::u16string_view i_rDestDataSource + ,const SharedConnection& _xConnection) +{ + if ( _rTransData.HasFormat(SotClipboardFormatId::DBACCESS_TABLE) || _rTransData.HasFormat(SotClipboardFormatId::DBACCESS_QUERY) ) + pasteTable( SotClipboardFormatId::DBACCESS_TABLE,_rTransData,i_rDestDataSource,_xConnection); + else if ( _rTransData.HasFormat(SotClipboardFormatId::HTML) ) + pasteTable( SotClipboardFormatId::HTML,_rTransData,i_rDestDataSource,_xConnection); + else if ( _rTransData.HasFormat(SotClipboardFormatId::RTF) ) + pasteTable( SotClipboardFormatId::RTF,_rTransData,i_rDestDataSource,_xConnection); +} + +bool OTableCopyHelper::copyTagTable(OTableCopyHelper::DropDescriptor const & _rDesc, bool _bCheck, const SharedConnection& _xConnection) +{ + rtl::Reference<ODatabaseImportExport> pImport; + if ( _rDesc.bHtml ) + pImport = new OHTMLImportExport(_xConnection,getNumberFormatter(_xConnection, m_pController->getORB()),m_pController->getORB()); + else + pImport = new ORTFImportExport(_xConnection,getNumberFormatter(_xConnection, m_pController->getORB()),m_pController->getORB()); + + SvStream* pStream = _rDesc.aHtmlRtfStorage.get(); + if ( _bCheck ) + pImport->enableCheckOnly(); + + //set the selected tablename + pImport->setSTableName(_rDesc.sDefaultTableName); + + pImport->setStream(pStream); + return pImport->Read(); +} + +bool OTableCopyHelper::isTableFormat(const TransferableDataHelper& _rClipboard) +{ + bool bTableFormat = _rClipboard.HasFormat(SotClipboardFormatId::DBACCESS_TABLE) + || _rClipboard.HasFormat(SotClipboardFormatId::DBACCESS_QUERY) + || _rClipboard.HasFormat(SotClipboardFormatId::RTF) + || _rClipboard.HasFormat(SotClipboardFormatId::HTML); + + return bTableFormat; +} + +bool OTableCopyHelper::copyTagTable(const TransferableDataHelper& _aDroppedData + ,DropDescriptor& _rAsyncDrop + ,const SharedConnection& _xConnection) +{ + bool bRet = false; + bool bHtml = _aDroppedData.HasFormat(SotClipboardFormatId::HTML); + if ( bHtml || _aDroppedData.HasFormat(SotClipboardFormatId::RTF) ) + { + bool bOk; + if ( bHtml ) + bOk = _aDroppedData.GetSotStorageStream(SotClipboardFormatId::HTML ,_rAsyncDrop.aHtmlRtfStorage); + else + bOk = _aDroppedData.GetSotStorageStream(SotClipboardFormatId::RTF,_rAsyncDrop.aHtmlRtfStorage); + + _rAsyncDrop.bHtml = bHtml; + _rAsyncDrop.bError = !copyTagTable(_rAsyncDrop,true,_xConnection); + + bRet = ( !_rAsyncDrop.bError && bOk && _rAsyncDrop.aHtmlRtfStorage.is() ); + if ( bRet ) + { + // now we need to copy the stream + ::utl::TempFile aTmp; + _rAsyncDrop.aUrl = aTmp.GetURL(); + ::tools::SvRef<SotTempStream> aNew = new SotTempStream( aTmp.GetFileName() ); + _rAsyncDrop.aHtmlRtfStorage->Seek(STREAM_SEEK_TO_BEGIN); + _rAsyncDrop.aHtmlRtfStorage->CopyTo( aNew.get() ); + _rAsyncDrop.aHtmlRtfStorage = aNew; + } + else + _rAsyncDrop.aHtmlRtfStorage = nullptr; + } + return bRet; +} + +void OTableCopyHelper::asyncCopyTagTable( DropDescriptor& _rDesc + ,std::u16string_view i_rDestDataSource + ,const SharedConnection& _xConnection) +{ + if ( _rDesc.aHtmlRtfStorage.is() ) + { + copyTagTable(_rDesc,false,_xConnection); + _rDesc.aHtmlRtfStorage = nullptr; + // we now have to delete the temp file created in executeDrop + INetURLObject aURL; + aURL.SetURL(_rDesc.aUrl); + ::utl::UCBContentHelper::Kill(aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE)); + } + else if ( !_rDesc.bError ) + pasteTable(_rDesc.aDroppedData,i_rDestDataSource,_xConnection); + else + m_pController->showError(SQLException(DBA_RES(STR_NO_TABLE_FORMAT_INSIDE), *m_pController, "S1000", 0, Any())); +} + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/misc/TokenWriter.cxx b/dbaccess/source/ui/misc/TokenWriter.cxx new file mode 100644 index 000000000..974337e8a --- /dev/null +++ b/dbaccess/source/ui/misc/TokenWriter.cxx @@ -0,0 +1,965 @@ +/* -*- 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 <TokenWriter.hxx> +#include <tools/diagnose_ex.h> +#include <tools/stream.hxx> +#include <osl/diagnose.h> +#include <rtl/tencinfo.h> +#include <sal/log.hxx> +#include <i18nlangtag/languagetag.hxx> +#include <RtfReader.hxx> +#include <HtmlReader.hxx> +#include <strings.hxx> +#include <comphelper/types.hxx> +#include <connectivity/dbtools.hxx> +#include <com/sun/star/sdb/CommandType.hpp> +#include <com/sun/star/sdb/DatabaseContext.hpp> +#include <com/sun/star/sdbc/XConnection.hpp> +#include <com/sun/star/sdbcx/XColumnsSupplier.hpp> +#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp> +#include <com/sun/star/sdbc/XRowSet.hpp> +#include <com/sun/star/sdbcx/XTablesSupplier.hpp> +#include <com/sun/star/sdb/XQueriesSupplier.hpp> +#include <com/sun/star/awt/FontWeight.hpp> +#include <com/sun/star/awt/FontStrikeout.hpp> +#include <com/sun/star/awt/FontSlant.hpp> +#include <com/sun/star/awt/FontUnderline.hpp> +#include <com/sun/star/document/DocumentProperties.hpp> +#include <svtools/htmlkywd.hxx> +#include <svtools/rtfkeywd.hxx> +#include <tools/color.hxx> +#include <svtools/htmlout.hxx> +#include <sfx2/frmhtmlw.hxx> +#include <svl/numuno.hxx> +#include <vcl/svapp.hxx> +#include <UITools.hxx> +#include <toolkit/helper/vclunohelper.hxx> +#include <vcl/outdev.hxx> +#include <vcl/settings.hxx> +#include <svtools/rtfout.hxx> +#include <svtools/htmlcfg.hxx> +#include <o3tl/string_view.hxx> +#include <connectivity/formattedcolumnvalue.hxx> +#include <memory> + +using namespace dbaui; +using namespace dbtools; +using namespace svx; +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::sdb; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::awt; +using namespace ::com::sun::star::util; + +#define CELL_X 1437 + +ODatabaseImportExport::ODatabaseImportExport(const svx::ODataAccessDescriptor& _aDataDescriptor, + const Reference< XComponentContext >& _rM, + const Reference< css::util::XNumberFormatter >& _rxNumberF) + :m_bBookmarkSelection( false ) + ,m_pStream(nullptr) + ,m_xFormatter(_rxNumberF) + ,m_xContext(_rM) + ,m_nCommandType(CommandType::TABLE) + ,m_bNeedToReInitialize(false) + ,m_bInInitialize(false) + ,m_bCheckOnly(false) +{ + m_eDestEnc = osl_getThreadTextEncoding(); + + osl_atomic_increment( &m_refCount ); + impl_initFromDescriptor( _aDataDescriptor, false ); + osl_atomic_decrement( &m_refCount ); +} + +// import data +ODatabaseImportExport::ODatabaseImportExport( const ::dbtools::SharedConnection& _rxConnection, + const Reference< XNumberFormatter >& _rxNumberF, const Reference< XComponentContext >& _rM ) + :m_bBookmarkSelection( false ) + ,m_pStream(nullptr) + ,m_xConnection(_rxConnection) + ,m_xFormatter(_rxNumberF) + ,m_xContext(_rM) + ,m_nCommandType(css::sdb::CommandType::TABLE) + ,m_bNeedToReInitialize(false) + ,m_bInInitialize(false) + ,m_bCheckOnly(false) +{ + m_eDestEnc = osl_getThreadTextEncoding(); +} + +ODatabaseImportExport::~ODatabaseImportExport() +{ + acquire(); + dispose(); +} + +void ODatabaseImportExport::dispose() +{ + // remove me as listener + Reference< XComponent > xComponent(m_xConnection, UNO_QUERY); + if (xComponent.is()) + { + Reference< XEventListener> xEvt(this); + xComponent->removeEventListener(xEvt); + } + m_xConnection.clear(); + + ::comphelper::disposeComponent(m_xRow); + + m_xObject.clear(); + m_xResultSetMetaData.clear(); + m_xResultSet.clear(); + m_xRow.clear(); + m_xRowLocate.clear(); + m_xFormatter.clear(); +} + +void SAL_CALL ODatabaseImportExport::disposing( const EventObject& Source ) +{ + Reference<XConnection> xCon(Source.Source,UNO_QUERY); + if(m_xConnection.is() && m_xConnection == xCon) + { + m_xConnection.clear(); + dispose(); + m_bNeedToReInitialize = true; + } +} + +void ODatabaseImportExport::initialize( const ODataAccessDescriptor& _aDataDescriptor ) +{ + impl_initFromDescriptor( _aDataDescriptor, true ); +} + +void ODatabaseImportExport::impl_initFromDescriptor( const ODataAccessDescriptor& _aDataDescriptor, bool _bPlusDefaultInit) +{ + if ( !_bPlusDefaultInit ) + { + m_sDataSourceName = _aDataDescriptor.getDataSource(); + _aDataDescriptor[DataAccessDescriptorProperty::CommandType] >>= m_nCommandType; + _aDataDescriptor[DataAccessDescriptorProperty::Command] >>= m_sName; + // some additional information + if(_aDataDescriptor.has(DataAccessDescriptorProperty::Connection)) + { + Reference< XConnection > xPureConn( _aDataDescriptor[DataAccessDescriptorProperty::Connection], UNO_QUERY ); + m_xConnection.reset( xPureConn, SharedConnection::NoTakeOwnership ); + Reference< XEventListener> xEvt(this); + Reference< XComponent > xComponent(m_xConnection, UNO_QUERY); + if (xComponent.is() && xEvt.is()) + xComponent->addEventListener(xEvt); + } + + if ( _aDataDescriptor.has( DataAccessDescriptorProperty::Selection ) ) + _aDataDescriptor[ DataAccessDescriptorProperty::Selection ] >>= m_aSelection; + + if ( _aDataDescriptor.has( DataAccessDescriptorProperty::BookmarkSelection ) ) + _aDataDescriptor[ DataAccessDescriptorProperty::BookmarkSelection ] >>= m_bBookmarkSelection; + + if ( _aDataDescriptor.has( DataAccessDescriptorProperty::Cursor ) ) + { + _aDataDescriptor[ DataAccessDescriptorProperty::Cursor ] >>= m_xResultSet; + m_xRowLocate.set( m_xResultSet, UNO_QUERY ); + } + + if ( m_aSelection.hasElements() ) + { + if ( !m_xResultSet.is() ) + { + SAL_WARN("dbaccess.ui", "ODatabaseImportExport::impl_initFromDescriptor: selection without result set is nonsense!" ); + m_aSelection.realloc( 0 ); + } + } + + if ( m_aSelection.hasElements() ) + { + if ( m_bBookmarkSelection && !m_xRowLocate.is() ) + { + SAL_WARN("dbaccess.ui", "ODatabaseImportExport::impl_initFromDescriptor: no XRowLocate -> no bookmarks!" ); + m_aSelection.realloc( 0 ); + } + } + } + else + initialize(); +} + +void ODatabaseImportExport::initialize() +{ + m_bInInitialize = true; + m_bNeedToReInitialize = false; + + if ( !m_xConnection.is() ) + { // we need a connection + OSL_ENSURE(!m_sDataSourceName.isEmpty(),"There must be a datsource name!"); + Reference<XNameAccess> xDatabaseContext( DatabaseContext::create(m_xContext), UNO_QUERY_THROW); + Reference< XEventListener> xEvt(this); + + Reference< XConnection > xConnection; + SQLExceptionInfo aInfo = ::dbaui::createConnection( m_sDataSourceName, xDatabaseContext, m_xContext, xEvt, xConnection ); + m_xConnection.reset( xConnection ); + + if(aInfo.isValid() && aInfo.getType() == SQLExceptionInfo::TYPE::SQLException) + throw *static_cast<const SQLException*>(aInfo); + } + + Reference<XNameAccess> xNameAccess; + switch(m_nCommandType) + { + case CommandType::TABLE: + { + // only for tables + Reference<XTablesSupplier> xSup(m_xConnection,UNO_QUERY); + if(xSup.is()) + xNameAccess = xSup->getTables(); + } + break; + case CommandType::QUERY: + { + Reference<XQueriesSupplier> xSup(m_xConnection,UNO_QUERY); + if(xSup.is()) + xNameAccess = xSup->getQueries(); + } + break; + } + if(xNameAccess.is() && xNameAccess->hasByName(m_sName)) + { + xNameAccess->getByName(m_sName) >>= m_xObject; + } + + if(m_xObject.is()) + { + try + { + if(m_xObject->getPropertySetInfo()->hasPropertyByName(PROPERTY_FONT)) + m_xObject->getPropertyValue(PROPERTY_FONT) >>= m_aFont; + + // the result set may be already set with the datadescriptor + if ( !m_xResultSet.is() ) + { + m_xResultSet.set( m_xContext->getServiceManager()->createInstanceWithContext("com.sun.star.sdb.RowSet", m_xContext), UNO_QUERY ); + Reference< XPropertySet > xProp( m_xResultSet, UNO_QUERY_THROW ); + xProp->setPropertyValue( PROPERTY_ACTIVE_CONNECTION, Any( m_xConnection.getTyped() ) ); + xProp->setPropertyValue( PROPERTY_COMMAND_TYPE, Any( m_nCommandType ) ); + xProp->setPropertyValue( PROPERTY_COMMAND, Any( m_sName ) ); + Reference< XRowSet > xRowSet( xProp, UNO_QUERY ); + xRowSet->execute(); + } + if ( !m_xRow.is() && m_xResultSet.is() ) + { + m_xRow.set( m_xResultSet, UNO_QUERY ); + m_xRowLocate.set( m_xResultSet, UNO_QUERY ); + m_xResultSetMetaData = Reference<XResultSetMetaDataSupplier>(m_xRow,UNO_QUERY_THROW)->getMetaData(); + Reference<XColumnsSupplier> xSup(m_xResultSet,UNO_QUERY_THROW); + m_xRowSetColumns.set(xSup->getColumns(),UNO_QUERY_THROW); + } + } + catch(Exception& ) + { + m_xRow = nullptr; + m_xResultSetMetaData = nullptr; + ::comphelper::disposeComponent(m_xResultSet); + throw; + } + } + if ( m_aFont.Name.isEmpty() ) + { + vcl::Font aApplicationFont = OutputDevice::GetDefaultFont( + DefaultFontType::SANS_UNICODE, + Application::GetSettings().GetUILanguageTag().getLanguageType(), + GetDefaultFontFlags::OnlyOne + ); + m_aFont = VCLUnoHelper::CreateFontDescriptor( aApplicationFont ); + } + + m_bInInitialize = false; +} + +bool ODatabaseImportExport::Write() +{ + if ( m_bNeedToReInitialize ) + { + if ( !m_bInInitialize ) + initialize(); + } + return true; +} + +bool ODatabaseImportExport::Read() +{ + if ( m_bNeedToReInitialize ) + { + if ( !m_bInInitialize ) + initialize(); + } + return true; +} + +bool ORTFImportExport::Write() +{ + ODatabaseImportExport::Write(); + m_pStream->WriteChar( '{' ).WriteCharPtr( OOO_STRING_SVTOOLS_RTF_RTF ); + m_pStream->WriteCharPtr(OOO_STRING_SVTOOLS_RTF_ANSI); + if (sal_uInt32 nCpg = rtl_getWindowsCodePageFromTextEncoding(m_eDestEnc); nCpg && nCpg != 65001) + { + m_pStream->WriteCharPtr(OOO_STRING_SVTOOLS_RTF_ANSICPG).WriteUInt32AsString(nCpg); + } + m_pStream->WriteCharPtr(SAL_NEWLINE_STRING); + + bool bBold = ( css::awt::FontWeight::BOLD == m_aFont.Weight ); + bool bItalic = ( css::awt::FontSlant_ITALIC == m_aFont.Slant ); + bool bUnderline = ( css::awt::FontUnderline::NONE != m_aFont.Underline ); + bool bStrikeout = ( css::awt::FontStrikeout::NONE != m_aFont.Strikeout ); + + ::Color aColor; + if(m_xObject.is()) + m_xObject->getPropertyValue(PROPERTY_TEXTCOLOR) >>= aColor; + + OString aFonts(OUStringToOString(m_aFont.Name, RTL_TEXTENCODING_MS_1252)); + if (aFonts.isEmpty()) + { + OUString aName = Application::GetSettings().GetStyleSettings().GetAppFont().GetFamilyName(); + aFonts = OUStringToOString(aName, RTL_TEXTENCODING_MS_1252); + } + + m_pStream->WriteCharPtr( "{\\fonttbl" ); + if (!aFonts.isEmpty()) + { + sal_Int32 nIdx{0}; + sal_Int32 nTok{-1}; // to compensate pre-increment + do { + m_pStream->WriteCharPtr( "\\f" ); + m_pStream->WriteInt32AsString(++nTok); + m_pStream->WriteCharPtr( "\\fcharset0\\fnil " ); + m_pStream->WriteOString( o3tl::getToken(aFonts, 0, ';', nIdx) ); + m_pStream->WriteChar( ';' ); + } while (nIdx>=0); + } + m_pStream->WriteChar( '}' ) ; + m_pStream->WriteCharPtr( SAL_NEWLINE_STRING ); + // write the rtf color table + m_pStream->WriteChar( '{' ).WriteCharPtr( OOO_STRING_SVTOOLS_RTF_COLORTBL ).WriteCharPtr( OOO_STRING_SVTOOLS_RTF_RED ); + m_pStream->WriteUInt32AsString(aColor.GetRed()); + m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_GREEN ); + m_pStream->WriteUInt32AsString(aColor.GetGreen()); + m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_BLUE ); + m_pStream->WriteUInt32AsString(aColor.GetBlue()); + + m_pStream->WriteCharPtr( ";\\red255\\green255\\blue255;\\red192\\green192\\blue192;}" ) + .WriteCharPtr( SAL_NEWLINE_STRING ); + + static char const aCell1[] = "\\clbrdrl\\brdrs\\brdrcf0\\clbrdrt\\brdrs\\brdrcf0\\clbrdrb\\brdrs\\brdrcf0\\clbrdrr\\brdrs\\brdrcf0\\clshdng10000\\clcfpat2\\cellx"; + + m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_TROWD ).WriteCharPtr( OOO_STRING_SVTOOLS_RTF_TRGAPH ); + m_pStream->WriteInt32AsString(40); + m_pStream->WriteCharPtr( SAL_NEWLINE_STRING ); + + if(m_xObject.is()) + { + Reference<XColumnsSupplier> xColSup(m_xObject,UNO_QUERY); + Reference<XNameAccess> xColumns = xColSup->getColumns(); + Sequence< OUString> aNames(xColumns->getElementNames()); + const OUString* pIter = aNames.getConstArray(); + + sal_Int32 nCount = aNames.getLength(); + bool bUseResultMetaData = false; + if ( !nCount ) + { + nCount = m_xResultSetMetaData->getColumnCount(); + bUseResultMetaData = true; + } + + for( sal_Int32 i=1; i<=nCount; ++i ) + { + m_pStream->WriteCharPtr( aCell1 ); + m_pStream->WriteInt32AsString(i*CELL_X); + m_pStream->WriteCharPtr( SAL_NEWLINE_STRING ); + } + + // column description + m_pStream->WriteChar( '{' ).WriteCharPtr( SAL_NEWLINE_STRING ); + m_pStream->WriteCharPtr( "\\trrh-270\\pard\\intbl" ); + + std::unique_ptr<OString[]> pHorzChar(new OString[nCount]); + + for ( sal_Int32 i=1; i <= nCount; ++i ) + { + sal_Int32 nAlign = 0; + OUString sColumnName; + if ( bUseResultMetaData ) + sColumnName = m_xResultSetMetaData->getColumnName(i); + else + { + sColumnName = *pIter; + Reference<XPropertySet> xColumn; + xColumns->getByName(sColumnName) >>= xColumn; + xColumn->getPropertyValue(PROPERTY_ALIGN) >>= nAlign; + ++pIter; + } + + const char* pChar; + switch( nAlign ) + { + case 1: pChar = OOO_STRING_SVTOOLS_RTF_QC; break; + case 2: pChar = OOO_STRING_SVTOOLS_RTF_QR; break; + case 0: + default:pChar = OOO_STRING_SVTOOLS_RTF_QL; break; + } + + pHorzChar[i-1] = pChar; // to avoid to always rummage in the ITEMSET later on + + m_pStream->WriteCharPtr( SAL_NEWLINE_STRING ); + m_pStream->WriteChar( '{' ); + m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_QC ); // column header always centered + + if ( bBold ) m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_B ); + if ( bItalic ) m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_I ); + if ( bUnderline ) m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_UL ); + if ( bStrikeout ) m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_STRIKE ); + + m_pStream->WriteCharPtr( "\\fs20\\f0\\cf0\\cb2" ); + m_pStream->WriteChar( ' ' ); + RTFOutFuncs::Out_String(*m_pStream, sColumnName, m_eDestEnc); + + m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_CELL ); + m_pStream->WriteChar( '}' ); + m_pStream->WriteCharPtr( SAL_NEWLINE_STRING ); + m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_PARD ).WriteCharPtr( OOO_STRING_SVTOOLS_RTF_INTBL ); + } + + m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_ROW ); + m_pStream->WriteCharPtr( SAL_NEWLINE_STRING ).WriteChar( '}' ); + m_pStream->WriteCharPtr( SAL_NEWLINE_STRING ); + + sal_Int32 k=1; + sal_Int32 kk=0; + if ( m_aSelection.hasElements() ) + { + const Any* pSelIter = m_aSelection.getConstArray(); + const Any* pEnd = pSelIter + m_aSelection.getLength(); + + bool bContinue = true; + for( ; pSelIter != pEnd && bContinue; ++pSelIter ) + { + if ( m_bBookmarkSelection ) + { + bContinue = m_xRowLocate->moveToBookmark( *pSelIter ); + } + else + { + sal_Int32 nPos = -1; + OSL_VERIFY( *pSelIter >>= nPos ); + bContinue = ( m_xResultSet->absolute( nPos ) ); + } + + if ( bContinue ) + appendRow( pHorzChar.get(), nCount, k, kk ); + } + } + else + { + m_xResultSet->beforeFirst(); // set back before the first row + while(m_xResultSet->next()) + { + appendRow(pHorzChar.get(),nCount,k,kk); + } + } + } + + m_pStream->WriteChar( '}' ).WriteCharPtr( SAL_NEWLINE_STRING ); + m_pStream->WriteUChar( 0 ); + return ((*m_pStream).GetError() == ERRCODE_NONE); +} + +void ORTFImportExport::appendRow(OString const * pHorzChar,sal_Int32 _nColumnCount,sal_Int32& k,sal_Int32& kk) +{ + ++kk; + m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_TROWD ).WriteCharPtr( OOO_STRING_SVTOOLS_RTF_TRGAPH ); + m_pStream->WriteInt32AsString(40); + m_pStream->WriteCharPtr( SAL_NEWLINE_STRING ); + + static char const aCell2[] = "\\clbrdrl\\brdrs\\brdrcf2\\clbrdrt\\brdrs\\brdrcf2\\clbrdrb\\brdrs\\brdrcf2\\clbrdrr\\brdrs\\brdrcf2\\clshdng10000\\clcfpat1\\cellx"; + + for ( sal_Int32 i=1; i<=_nColumnCount; ++i ) + { + m_pStream->WriteCharPtr( aCell2 ); + m_pStream->WriteInt32AsString(i*CELL_X); + m_pStream->WriteCharPtr( SAL_NEWLINE_STRING ); + } + + const bool bBold = ( css::awt::FontWeight::BOLD == m_aFont.Weight ); + const bool bItalic = ( css::awt::FontSlant_ITALIC == m_aFont.Slant ); + const bool bUnderline = ( css::awt::FontUnderline::NONE != m_aFont.Underline ); + const bool bStrikeout = ( css::awt::FontStrikeout::NONE != m_aFont.Strikeout ); + Reference< XRowSet > xRowSet(m_xRow,UNO_QUERY); + + m_pStream->WriteChar( '{' ); + m_pStream->WriteCharPtr( "\\trrh-270\\pard\\intbl" ); + for ( sal_Int32 i=1; i <= _nColumnCount; ++i ) + { + m_pStream->WriteCharPtr( SAL_NEWLINE_STRING ); + m_pStream->WriteChar( '{' ); + m_pStream->WriteOString( pHorzChar[i-1] ); + + if ( bBold ) m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_B ); + if ( bItalic ) m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_I ); + if ( bUnderline ) m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_UL ); + if ( bStrikeout ) m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_STRIKE ); + + m_pStream->WriteCharPtr( "\\fs20\\f1\\cf0\\cb1 " ); + + try + { + Reference<XPropertySet> xColumn(m_xRowSetColumns->getByIndex(i-1),UNO_QUERY_THROW); + dbtools::FormattedColumnValue aFormatedValue(m_xContext,xRowSet,xColumn); + OUString sValue = aFormatedValue.getFormattedValue(); + if ( !sValue.isEmpty() ) + RTFOutFuncs::Out_String(*m_pStream,sValue,m_eDestEnc); + } + catch (Exception&) + { + SAL_WARN("dbaccess.ui","RTF WRITE!"); + } + + m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_CELL ); + m_pStream->WriteChar( '}' ); + m_pStream->WriteCharPtr( SAL_NEWLINE_STRING ); + m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_PARD ).WriteCharPtr( OOO_STRING_SVTOOLS_RTF_INTBL ); + } + m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_ROW ).WriteCharPtr( SAL_NEWLINE_STRING ); + m_pStream->WriteChar( '}' ); + ++k; +} + +bool ORTFImportExport::Read() +{ + ODatabaseImportExport::Read(); + SvParserState eState = SvParserState::Error; + if ( m_pStream ) + { + tools::SvRef<ORTFReader> xReader(new ORTFReader((*m_pStream),m_xConnection,m_xFormatter,m_xContext)); + if ( isCheckEnabled() ) + xReader->enableCheckOnly(); + eState = xReader->CallParser(); + } + + return eState != SvParserState::Error; +} + +const sal_Int16 OHTMLImportExport::nCellSpacing = 0; +const char OHTMLImportExport::sIndentSource[nIndentMax+1] = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"; + +OHTMLImportExport::OHTMLImportExport(const svx::ODataAccessDescriptor& _aDataDescriptor, + const Reference< XComponentContext >& _rM, + const Reference< css::util::XNumberFormatter >& _rxNumberF) + : ODatabaseImportExport(_aDataDescriptor,_rM,_rxNumberF) + ,m_nIndent(0) +#if OSL_DEBUG_LEVEL > 0 + ,m_bCheckFont(false) +#endif +{ + // set HTML configuration + m_eDestEnc = RTL_TEXTENCODING_UTF8; + strncpy( sIndent, sIndentSource ,std::min(sizeof(sIndent),sizeof(sIndentSource))); + sIndent[0] = 0; +} + +bool OHTMLImportExport::Write() +{ + ODatabaseImportExport::Write(); + if(m_xObject.is()) + { + m_pStream->WriteChar( '<' ).WriteCharPtr( OOO_STRING_SVTOOLS_HTML_doctype ).WriteChar( ' ' ).WriteCharPtr( OOO_STRING_SVTOOLS_HTML_doctype5 ).WriteChar( '>' ).WriteCharPtr( SAL_NEWLINE_STRING ).WriteCharPtr( SAL_NEWLINE_STRING ); + HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_html).WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr()); + WriteHeader(); + m_pStream->WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr()); + WriteBody(); + m_pStream->WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr()); + HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_html, false).WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr()); + + return ((*m_pStream).GetError() == ERRCODE_NONE); + } + return false; +} + +bool OHTMLImportExport::Read() +{ + ODatabaseImportExport::Read(); + SvParserState eState = SvParserState::Error; + if ( m_pStream ) + { + tools::SvRef<OHTMLReader> xReader(new OHTMLReader((*m_pStream),m_xConnection,m_xFormatter,m_xContext)); + if ( isCheckEnabled() ) + xReader->enableCheckOnly(); + xReader->SetTableName(m_sDefaultTableName); + eState = xReader->CallParser(); + } + + return eState != SvParserState::Error; +} + +void OHTMLImportExport::WriteHeader() +{ + uno::Reference<document::XDocumentProperties> xDocProps( + document::DocumentProperties::create( m_xContext ) ); + if (xDocProps.is()) { + xDocProps->setTitle(m_sName); + } + + IncIndent(1); + HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_head).WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr()); + + SfxFrameHTMLWriter::Out_DocInfo( (*m_pStream), OUString(), + xDocProps, sIndent ); + m_pStream->WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr()); + IncIndent(-1); + m_pStream->WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr()); + HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_head, false).WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr()); +} + +void OHTMLImportExport::WriteBody() +{ + IncIndent(1); + m_pStream->WriteCharPtr( "<" ).WriteCharPtr( OOO_STRING_SVTOOLS_HTML_style ).WriteCharPtr( " " ).WriteCharPtr( OOO_STRING_SVTOOLS_HTML_O_type ).WriteCharPtr( "=\"text/css\">" ); + + m_pStream->WriteCharPtr( "<!-- " ); + m_pStream->WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr()); + m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_HTML_body ).WriteCharPtr( " { " ).WriteCharPtr( "font-family: " ).WriteChar( '"' ).WriteOString( OUStringToOString(m_aFont.Name, osl_getThreadTextEncoding()) ).WriteChar( '\"' ); + // TODO : think about the encoding of the font name + m_pStream->WriteCharPtr( "; " ).WriteCharPtr( "font-size: " ); + m_pStream->WriteInt32AsString(m_aFont.Height); + m_pStream->WriteChar( '}' ); + + m_pStream->WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr()); + m_pStream->WriteCharPtr( " -->" ); + IncIndent(-1); + m_pStream->WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr()); + HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_style, false).WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr()); + m_pStream->WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr()); + + // default Textcolour black + m_pStream->WriteChar( '<' ).WriteCharPtr( OOO_STRING_SVTOOLS_HTML_body ).WriteChar( ' ' ).WriteCharPtr( OOO_STRING_SVTOOLS_HTML_O_text ).WriteChar( '=' ); + ::Color aColor; + if(m_xObject.is()) + m_xObject->getPropertyValue(PROPERTY_TEXTCOLOR) >>= aColor; + HTMLOutFuncs::Out_Color( (*m_pStream), aColor ); + + m_pStream->WriteCharPtr( " " OOO_STRING_SVTOOLS_HTML_O_bgcolor "=" ); + HTMLOutFuncs::Out_Color( (*m_pStream), aColor ); + + m_pStream->WriteChar( '>' ); + m_pStream->WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr()); + + WriteTables(); + + HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_body, false).WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr()); +} + +void OHTMLImportExport::WriteTables() +{ + OString aStrOut = OOO_STRING_SVTOOLS_HTML_table + " " + OOO_STRING_SVTOOLS_HTML_frame + "=" + OOO_STRING_SVTOOLS_HTML_TF_void; + + Sequence< OUString> aNames; + Reference<XNameAccess> xColumns; + bool bUseResultMetaData = false; + if(m_xObject.is()) + { + Reference<XColumnsSupplier> xColSup(m_xObject,UNO_QUERY); + xColumns = xColSup->getColumns(); + aNames = xColumns->getElementNames(); + if ( !aNames.hasElements() ) + { + sal_Int32 nCount = m_xResultSetMetaData->getColumnCount(); + aNames.realloc(nCount); + auto aNamesRange = asNonConstRange(aNames); + for (sal_Int32 i= 0; i < nCount; ++i) + aNamesRange[i] = m_xResultSetMetaData->getColumnName(i+1); + bUseResultMetaData = true; + } + } + + aStrOut += " " + OOO_STRING_SVTOOLS_HTML_O_align + "=" + OOO_STRING_SVTOOLS_HTML_AL_left + " " + OOO_STRING_SVTOOLS_HTML_O_cellspacing + "=" + + OString::number(nCellSpacing) + + " " + OOO_STRING_SVTOOLS_HTML_O_cols + "=" + + OString::number(aNames.getLength()) + + " " + OOO_STRING_SVTOOLS_HTML_O_border + "=1"; + + IncIndent(1); + HTMLOutFuncs::Out_AsciiTag(*m_pStream, aStrOut.getStr()); + + FontOn(); + + HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_caption); + HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_bold); + + m_pStream->WriteOString( OUStringToOString(m_sName, osl_getThreadTextEncoding()) ); + // TODO : think about the encoding of the name + HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_bold, false); + HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_caption, false); + + FontOff(); + m_pStream->WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr()); + // </FONT> + + IncIndent(1); + HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_thead).WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr()); + + IncIndent(1); + HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_tablerow).WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr()); + + if(m_xObject.is()) + { + std::unique_ptr<sal_Int32[]> pFormat(new sal_Int32[aNames.getLength()]); + + std::unique_ptr<const char *[]> pHorJustify(new const char*[aNames.getLength()]); + std::unique_ptr<sal_Int32[]> pColWidth(new sal_Int32[aNames.getLength()]); + + sal_Int32 nHeight = 0; + m_xObject->getPropertyValue(PROPERTY_ROW_HEIGHT) >>= nHeight; + + // 1. writing the column description + const OUString* pIter = aNames.getConstArray(); + const OUString* pEnd = pIter + aNames.getLength(); + + for( sal_Int32 i=0;pIter != pEnd; ++pIter,++i ) + { + sal_Int32 nAlign = 0; + pFormat[i] = 0; + pColWidth[i] = 100; + if ( !bUseResultMetaData ) + { + Reference<XPropertySet> xColumn; + xColumns->getByName(*pIter) >>= xColumn; + xColumn->getPropertyValue(PROPERTY_ALIGN) >>= nAlign; + pFormat[i] = ::comphelper::getINT32(xColumn->getPropertyValue(PROPERTY_FORMATKEY)); + pColWidth[i] = ::comphelper::getINT32(xColumn->getPropertyValue(PROPERTY_WIDTH)); + } + + switch( nAlign ) + { + case 1: pHorJustify[i] = OOO_STRING_SVTOOLS_HTML_AL_center; break; + case 2: pHorJustify[i] = OOO_STRING_SVTOOLS_HTML_AL_right; break; + default: pHorJustify[i] = OOO_STRING_SVTOOLS_HTML_AL_left; break; + } + + if(i == aNames.getLength()-1) + IncIndent(-1); + + WriteCell(pFormat[i],pColWidth[i],nHeight,pHorJustify[i],*pIter,OOO_STRING_SVTOOLS_HTML_tableheader); + } + + IncIndent(-1); + HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_tablerow, false).WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr()); + HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_thead, false).WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr()); + + IncIndent(1); + HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_tbody).WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr()); + + // 2. and now the data + Reference< XRowSet > xRowSet(m_xRow,UNO_QUERY); + m_xResultSet->beforeFirst(); // set back before the first row + while(m_xResultSet->next()) + { + IncIndent(1); + HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_tablerow).WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr()); + + for(sal_Int32 i=1;i<=aNames.getLength();++i) + { + if(i == aNames.getLength()) + IncIndent(-1); + + OUString aValue; + try + { + Reference<XPropertySet> xColumn(m_xRowSetColumns->getByIndex(i-1),UNO_QUERY_THROW); + dbtools::FormattedColumnValue aFormatedValue(m_xContext,xRowSet,xColumn); + OUString sValue = aFormatedValue.getFormattedValue(); + if (!sValue.isEmpty()) + { + aValue = sValue; + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + WriteCell(pFormat[i-1],pColWidth[i-1],nHeight,pHorJustify[i-1],aValue,OOO_STRING_SVTOOLS_HTML_tabledata); + } + HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_tablerow, false).WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr()); + } + } + else + { + IncIndent(-1); + HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_tablerow, false).WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr()); + HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_thead, false).WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr()); + + IncIndent(1); + HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_tbody).WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr()); + } + + IncIndent(-1); + m_pStream->WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr()); + HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_tbody, false).WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr()); + IncIndent(-1); + HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_table, false).WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr()); +} + +void OHTMLImportExport::WriteCell( sal_Int32 nFormat, sal_Int32 nWidthPixel, sal_Int32 nHeightPixel, const char* pChar, + const OUString& rValue, const char* pHtmlTag) +{ + OString aStrTD = pHtmlTag; + + nWidthPixel = nWidthPixel ? nWidthPixel : 86; + nHeightPixel = nHeightPixel ? nHeightPixel : 17; + + // despite the <TABLE COLS=n> and <COL WIDTH=x> designation necessary, + // as Netscape is not paying attention to them. + // column width + aStrTD += " " + OOO_STRING_SVTOOLS_HTML_O_width + "=" + + OString::number(nWidthPixel) + + // line height + " " + OOO_STRING_SVTOOLS_HTML_O_height + "=" + + OString::number(nHeightPixel) + + " " + OOO_STRING_SVTOOLS_HTML_O_align + "=" + + pChar; + + SvNumberFormatsSupplierObj* pSupplierImpl = m_xFormatter.is() ? comphelper::getFromUnoTunnel<SvNumberFormatsSupplierObj>(m_xFormatter->getNumberFormatsSupplier()) : nullptr; + SvNumberFormatter* pFormatter = pSupplierImpl ? pSupplierImpl->GetNumberFormatter() : nullptr; + if(pFormatter) + { + double fVal = 0.0; + + try + { + fVal = m_xFormatter->convertStringToNumber(nFormat,rValue); + HTMLOutFuncs::CreateTableDataOptionsValNum(false, fVal,nFormat, *pFormatter); + } + catch(const Exception&) + { + HTMLOutFuncs::CreateTableDataOptionsValNum(false, fVal,nFormat, *pFormatter); + } + } + + HTMLOutFuncs::Out_AsciiTag(*m_pStream, aStrTD.getStr()); + + FontOn(); + + bool bBold = ( css::awt::FontWeight::BOLD == m_aFont.Weight ); + bool bItalic = ( css::awt::FontSlant_ITALIC == m_aFont.Slant ); + bool bUnderline = ( css::awt::FontUnderline::NONE != m_aFont.Underline ); + bool bStrikeout = ( css::awt::FontStrikeout::NONE != m_aFont.Strikeout ); + + if ( bBold ) HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_bold); + if ( bItalic ) HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_italic); + if ( bUnderline ) HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_underline); + if ( bStrikeout ) HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_strike); + + if ( rValue.isEmpty() ) + HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_linebreak); // no completely empty cell + else + HTMLOutFuncs::Out_String( (*m_pStream), rValue ); + + if ( bStrikeout ) HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_strike, false); + if ( bUnderline ) HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_underline, false); + if ( bItalic ) HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_italic, false); + if ( bBold ) HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_bold, false); + + FontOff(); + + HTMLOutFuncs::Out_AsciiTag(*m_pStream, pHtmlTag, false).WriteCharPtr(SAL_NEWLINE_STRING).WriteCharPtr(GetIndentStr()); +} + +void OHTMLImportExport::FontOn() +{ +#if OSL_DEBUG_LEVEL > 0 + m_bCheckFont = true; +#endif + + // <FONT FACE="xxx"> + OString aStrOut = "<" + OOO_STRING_SVTOOLS_HTML_font + " " + OOO_STRING_SVTOOLS_HTML_O_face + "=" + "\"" + + OUStringToOString(m_aFont.Name,osl_getThreadTextEncoding()) + + // TODO : think about the encoding of the font name + "\"" + " " + OOO_STRING_SVTOOLS_HTML_O_color + "="; + m_pStream->WriteOString( aStrOut ); + + ::Color aColor; + if(m_xObject.is()) + m_xObject->getPropertyValue(PROPERTY_TEXTCOLOR) >>= aColor; + + HTMLOutFuncs::Out_Color( (*m_pStream), aColor ); + m_pStream->WriteCharPtr( ">" ); +} + +inline void OHTMLImportExport::FontOff() +{ +#if OSL_DEBUG_LEVEL > 0 + OSL_ENSURE(m_bCheckFont,"No FontOn() called"); +#endif + HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_font, false); +#if OSL_DEBUG_LEVEL > 0 + m_bCheckFont = false; +#endif +} + +void OHTMLImportExport::IncIndent( sal_Int16 nVal ) +{ + sIndent[m_nIndent] = '\t'; + m_nIndent = m_nIndent + nVal; + if ( m_nIndent < 0 ) + m_nIndent = 0; + else if ( m_nIndent > nIndentMax ) + m_nIndent = nIndentMax; + sIndent[m_nIndent] = 0; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/misc/UITools.cxx b/dbaccess/source/ui/misc/UITools.cxx new file mode 100644 index 000000000..7a9553e49 --- /dev/null +++ b/dbaccess/source/ui/misc/UITools.cxx @@ -0,0 +1,1370 @@ +/* -*- 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 <UITools.hxx> +#include <sfx2/docfilt.hxx> +#include <core_resource.hxx> +#include <dlgsave.hxx> +#include <defaultobjectnamecheck.hxx> +#include <strings.hxx> +#include <comphelper/extract.hxx> +#include <com/sun/star/sdb/DatabaseContext.hpp> +#include <com/sun/star/sdb/XSingleSelectQueryAnalyzer.hpp> +#include <com/sun/star/sdb/XCompletedConnection.hpp> +#include <com/sun/star/sdbc/XDataSource.hpp> +#include <com/sun/star/sdb/SQLContext.hpp> +#include <com/sun/star/sdbcx/XColumnsSupplier.hpp> +#include <com/sun/star/sdbcx/XViewsSupplier.hpp> +#include <com/sun/star/sdbcx/XTablesSupplier.hpp> +#include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp> +#include <com/sun/star/sdbcx/XAppend.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp> +#include <com/sun/star/sdbc/XResultSetMetaData.hpp> +#include <com/sun/star/sdbc/ColumnValue.hpp> +#include <com/sun/star/task/InteractionHandler.hpp> +#include <com/sun/star/ucb/XContent.hpp> +#include <com/sun/star/ui/dialogs/XExecutableDialog.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/container/XNameContainer.hpp> +#include <com/sun/star/ucb/InteractiveIOException.hpp> +#include <com/sun/star/sdb/XDocumentDataSource.hpp> +#include <com/sun/star/ucb/IOErrorCode.hpp> +#include <vcl/syswin.hxx> +#include <vcl/settings.hxx> +#include <vcl/svapp.hxx> +#include <com/sun/star/beans/XPropertySetInfo.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/container/XNameAccess.hpp> +#include <com/sun/star/container/XHierarchicalNameContainer.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/awt/TextAlign.hpp> +#include <TypeInfo.hxx> +#include <FieldDescriptions.hxx> +#include <comphelper/stl_types.hxx> +#include <comphelper/types.hxx> +#include <comphelper/propertysequence.hxx> + +#include <svx/svxids.hrc> + +#include <sal/log.hxx> +#include <svl/numformat.hxx> +#include <svl/itempool.hxx> +#include <helpids.h> +#include <svl/itemset.hxx> +#include <sbagrid.hrc> +#include <svl/rngitem.hxx> +#include <svl/intitem.hxx> +#include <svx/numinf.hxx> +#include <svl/zforlist.hxx> +#include <dlgattr.hxx> +#include <com/sun/star/container/XChild.hpp> +#include <com/sun/star/util/NumberFormatter.hpp> +#include <com/sun/star/util/XNumberFormatsSupplier.hpp> +#include <com/sun/star/util/XNumberFormatter.hpp> +#include <strings.hrc> +#include <sqlmessage.hxx> +#include <dlgsize.hxx> +#include <svtools/editbrowsebox.hxx> +#include <tools/urlobj.hxx> +#include <tools/diagnose_ex.h> +#include <svl/numuno.hxx> +#include <svl/filenotation.hxx> +#include <connectivity/FValue.hxx> + +#include <editeng/justifyitem.hxx> +#include <memory> + +namespace dbaui +{ +using namespace ::dbtools; +using namespace ::comphelper; +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::task; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::sdb; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::ucb; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::ui::dialogs; +using namespace ::svt; +using ::com::sun::star::ucb::InteractiveIOException; +using ::com::sun::star::ucb::IOErrorCode_NO_FILE; +using ::com::sun::star::ucb::IOErrorCode_NOT_EXISTING; + +SQLExceptionInfo createConnection( const OUString& _rsDataSourceName, + const Reference< css::container::XNameAccess >& _xDatabaseContext, + const Reference< css::uno::XComponentContext >& _rxContext, + Reference< css::lang::XEventListener> const & _rEvtLst, + Reference< css::sdbc::XConnection>& _rOUTConnection ) +{ + Reference<XPropertySet> xProp; + try + { + xProp.set(_xDatabaseContext->getByName(_rsDataSourceName),UNO_QUERY); + } + catch(const Exception&) + { + } + + return createConnection(xProp,_rxContext,_rEvtLst,_rOUTConnection); +} + +SQLExceptionInfo createConnection( const Reference< css::beans::XPropertySet>& _xDataSource, + const Reference< css::uno::XComponentContext >& _rxContext, + Reference< css::lang::XEventListener> const & _rEvtLst, + Reference< css::sdbc::XConnection>& _rOUTConnection ) +{ + SQLExceptionInfo aInfo; + if ( !_xDataSource.is() ) + { + SAL_WARN("dbaccess.ui", "createConnection: could not retrieve the data source!"); + return aInfo; + } + + OUString sPwd, sUser; + bool bPwdReq = false; + try + { + _xDataSource->getPropertyValue(PROPERTY_PASSWORD) >>= sPwd; + bPwdReq = ::cppu::any2bool(_xDataSource->getPropertyValue(PROPERTY_ISPASSWORDREQUIRED)); + _xDataSource->getPropertyValue(PROPERTY_USER) >>= sUser; + } + catch(const Exception&) + { + SAL_WARN("dbaccess.ui", "createConnection: error while retrieving data source properties!"); + } + + try + { + if(bPwdReq && sPwd.isEmpty()) + { // password required, but empty -> connect using an interaction handler + Reference<XCompletedConnection> xConnectionCompletion(_xDataSource, UNO_QUERY); + if (!xConnectionCompletion.is()) + { + SAL_WARN("dbaccess.ui", "createConnection: missing an interface ... need an error message here!"); + } + else + { // instantiate the default SDB interaction handler + Reference< XInteractionHandler > xHandler = InteractionHandler::createWithParent(_rxContext, nullptr); + _rOUTConnection = xConnectionCompletion->connectWithCompletion(xHandler); + } + } + else + { + Reference<XDataSource> xDataSource(_xDataSource,UNO_QUERY); + _rOUTConnection = xDataSource->getConnection(sUser, sPwd); + } + // be notified when connection is in disposing + Reference< XComponent > xComponent(_rOUTConnection, UNO_QUERY); + if (xComponent.is() && _rEvtLst.is()) + xComponent->addEventListener(_rEvtLst); + } + catch(const SQLContext& e) { aInfo = SQLExceptionInfo(e); } + catch(const SQLWarning& e) { aInfo = SQLExceptionInfo(e); } + catch(const SQLException& e) { aInfo = SQLExceptionInfo(e); } + catch(const Exception&) { + TOOLS_WARN_EXCEPTION("dbaccess.ui", "SbaTableQueryBrowser::OnExpandEntry: could not connect - unknown exception"); + } + + return aInfo; +} + +Reference< XDataSource > getDataSourceByName( const OUString& _rDataSourceName, + weld::Window* _pErrorMessageParent, const Reference< XComponentContext >& _rxContext, ::dbtools::SQLExceptionInfo* _pErrorInfo ) +{ + Reference< XDatabaseContext > xDatabaseContext = DatabaseContext::create(_rxContext); + + Reference< XDataSource > xDatasource; + SQLExceptionInfo aSQLError; + try + { + xDatabaseContext->getByName( _rDataSourceName ) >>= xDatasource; + } + catch(const WrappedTargetException& e) + { + InteractiveIOException aIOException; + if ( ( e.TargetException >>= aIOException ) + && ( ( aIOException.Code == IOErrorCode_NO_FILE ) + || ( aIOException.Code == IOErrorCode_NOT_EXISTING ) + ) + ) + { + OUString sErrorMessage( DBA_RES( STR_FILE_DOES_NOT_EXIST ) ); + OFileNotation aTransformer( e.Message ); + sErrorMessage = sErrorMessage.replaceFirst( "$file$", aTransformer.get( OFileNotation::N_SYSTEM ) ); + aSQLError = SQLExceptionInfo( sErrorMessage ).get(); + } + else + { + aSQLError = SQLExceptionInfo( e.TargetException ); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + if ( xDatasource.is() ) + return xDatasource; + + if ( aSQLError.isValid() ) + { + if ( _pErrorInfo ) + { + *_pErrorInfo = aSQLError; + } + else + { + showError( aSQLError, _pErrorMessageParent ? _pErrorMessageParent->GetXWindow() : nullptr, _rxContext ); + } + } + + return Reference<XDataSource>(); +} + +Reference< XInterface > getDataSourceOrModel(const Reference< XInterface >& _xObject) +{ + Reference< XInterface > xRet; + Reference<XDocumentDataSource> xDocumentDataSource(_xObject,UNO_QUERY); + if ( xDocumentDataSource.is() ) + xRet = xDocumentDataSource->getDatabaseDocument(); + + if ( !xRet.is() ) + { + Reference<XOfficeDatabaseDocument> xOfficeDoc(_xObject,UNO_QUERY); + if ( xOfficeDoc.is() ) + xRet = xOfficeDoc->getDataSource(); + } + + return xRet; +} + +TOTypeInfoSP getTypeInfoFromType(const OTypeInfoMap& _rTypeInfo, + sal_Int32 _nType, + const OUString& _sTypeName, + const OUString& _sCreateParams, + sal_Int32 _nPrecision, + sal_Int32 _nScale, + bool _bAutoIncrement, + bool& _brForceToType) +{ + TOTypeInfoSP pTypeInfo; + _brForceToType = false; + // search for type + std::pair<OTypeInfoMap::const_iterator, OTypeInfoMap::const_iterator> aPair = _rTypeInfo.equal_range(_nType); + OTypeInfoMap::const_iterator aIter = aPair.first; + if(aIter != _rTypeInfo.end()) // compare with end is correct here + { + for(;aIter != aPair.second;++aIter) + { + // search the best matching type + #ifdef DBG_UTIL + OUString sDBTypeName = aIter->second->aTypeName; (void)sDBTypeName; + #endif + if ( ( + _sTypeName.isEmpty() + || (aIter->second->aTypeName.equalsIgnoreAsciiCase(_sTypeName)) + ) + && ( + ( + !aIter->second->aCreateParams.getLength() + && _sCreateParams.isEmpty() + ) + || ( + (aIter->second->nPrecision >= _nPrecision) + && (aIter->second->nMaximumScale >= _nScale) + && ( (_bAutoIncrement && aIter->second->bAutoIncrement) || !_bAutoIncrement ) + ) + ) + ) + break; + } + + if (aIter == aPair.second) + { + for(aIter = aPair.first; aIter != aPair.second; ++aIter) + { + sal_Int32 nPrec = aIter->second->nPrecision; + sal_Int32 nScale = aIter->second->nMaximumScale; + // search the best matching type (now comparing the local names) + if ( (aIter->second->aLocalTypeName.equalsIgnoreAsciiCase(_sTypeName)) + && (nPrec >= _nPrecision) + && (nScale >= _nScale) + && ( (_bAutoIncrement && aIter->second->bAutoIncrement) || !_bAutoIncrement ) + ) + { + SAL_WARN("dbaccess.ui", "getTypeInfoFromType: assuming column type " << + aIter->second->aTypeName << "\" (expected type name " << + _sTypeName << " matches the type's local name)."); + break; + } + } + } + + if (aIter == aPair.second) + { // no match for the names, no match for the local names + // -> drop the precision and the scale restriction, accept any type with the property + // type id (nType) + + for(aIter = aPair.first; aIter != aPair.second; ++aIter) + { + // search the best matching type (now comparing the local names) + sal_Int32 nPrec = aIter->second->nPrecision; + sal_Int32 nScale = aIter->second->nMaximumScale; + if ( (nPrec >= _nPrecision) + && (nScale >= _nScale) + && ( (_bAutoIncrement && aIter->second->bAutoIncrement) || !_bAutoIncrement ) + ) + break; + } + } + if (aIter == aPair.second) + { + if ( _bAutoIncrement ) + { + for(aIter = aPair.first; aIter != aPair.second; ++aIter) + { + // search the best matching type (now comparing the local names) + sal_Int32 nScale = aIter->second->nMaximumScale; + if ( (nScale >= _nScale) + && (aIter->second->bAutoIncrement == _bAutoIncrement) + ) + break; + } + if ( aIter == aPair.second ) + { + // try it without the auto increment flag + pTypeInfo = getTypeInfoFromType(_rTypeInfo, + _nType, + _sTypeName, + _sCreateParams, + _nPrecision, + _nScale, + false, + _brForceToType); + } + else + pTypeInfo = aIter->second; + } + else + { + pTypeInfo = aPair.first->second; + _brForceToType = true; + } + } + else + pTypeInfo = aIter->second; + } + else + { + ::comphelper::UStringMixEqual aCase(false); + // search for typeinfo where the typename is equal _sTypeName + for (auto const& elem : _rTypeInfo) + { + if ( aCase( elem.second->getDBName() , _sTypeName ) ) + { + pTypeInfo = elem.second; + break; + } + } + } + + OSL_ENSURE(pTypeInfo, "getTypeInfoFromType: no type info found for this type!"); + return pTypeInfo; +} + +void fillTypeInfo( const Reference< css::sdbc::XConnection>& _rxConnection, + std::u16string_view _rsTypeNames, + OTypeInfoMap& _rTypeInfoMap, + std::vector<OTypeInfoMap::iterator>& _rTypeInfoIters) +{ + if(!_rxConnection.is()) + return; + Reference< XResultSet> xRs = _rxConnection->getMetaData ()->getTypeInfo (); + Reference< XRow> xRow(xRs,UNO_QUERY); + // Information for a single SQL type + if(!xRs.is()) + return; + + Reference<XResultSetMetaData> xResultSetMetaData = Reference<XResultSetMetaDataSupplier>(xRs,UNO_QUERY_THROW)->getMetaData(); + ::connectivity::ORowSetValue aValue; + std::vector<sal_Int32> aTypes; + std::vector<bool> aNullable; + // Loop on the result set until we reach end of file + while (xRs->next()) + { + TOTypeInfoSP pInfo = std::make_shared<OTypeInfo>(); + sal_Int32 nPos = 1; + if ( aTypes.empty() ) + { + sal_Int32 nCount = xResultSetMetaData->getColumnCount(); + if ( nCount < 1 ) + nCount = 18; + aTypes.reserve(nCount+1); + aTypes.push_back(-1); + aNullable.push_back(false); + for (sal_Int32 j = 1; j <= nCount ; ++j) + { + aTypes.push_back(xResultSetMetaData->getColumnType(j)); + aNullable.push_back(xResultSetMetaData->isNullable(j) != ColumnValue::NO_NULLS); + } + } + + aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); + pInfo->aTypeName = aValue.getString(); + ++nPos; + aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); + pInfo->nType = aValue.getInt32(); + ++nPos; + aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); + pInfo->nPrecision = aValue.getInt32(); + ++nPos; + aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); // LiteralPrefix + ++nPos; + aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); //LiteralSuffix + ++nPos; + aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); + pInfo->aCreateParams = aValue.getString(); + ++nPos; + aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); + pInfo->bNullable = aValue.getInt32() == ColumnValue::NULLABLE; + ++nPos; + aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); + // bCaseSensitive + ++nPos; + aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); + pInfo->nSearchType = aValue.getInt16(); + ++nPos; + aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); + // bUnsigned + ++nPos; + aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); + pInfo->bCurrency = aValue.getBool(); + ++nPos; + aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); + pInfo->bAutoIncrement = aValue.getBool(); + ++nPos; + aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); + pInfo->aLocalTypeName = aValue.getString(); + ++nPos; + aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); + pInfo->nMinimumScale = aValue.getInt16(); + ++nPos; + aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); + pInfo->nMaximumScale = aValue.getInt16(); + assert(nPos == 15); + // 16 and 17 are unused + nPos = 18; + aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); + pInfo->nNumPrecRadix = aValue.getInt32(); + + // check if values are less than zero like it happens in a oracle jdbc driver + if( pInfo->nPrecision < 0) + pInfo->nPrecision = 0; + if( pInfo->nMinimumScale < 0) + pInfo->nMinimumScale = 0; + if( pInfo->nMaximumScale < 0) + pInfo->nMaximumScale = 0; + if( pInfo->nNumPrecRadix <= 1) + pInfo->nNumPrecRadix = 10; + + std::u16string_view aName; + switch(pInfo->nType) + { + case DataType::CHAR: + aName = o3tl::getToken(_rsTypeNames, TYPE_CHAR, ';'); + break; + case DataType::VARCHAR: + aName = o3tl::getToken(_rsTypeNames, TYPE_TEXT, ';'); + break; + case DataType::DECIMAL: + aName = o3tl::getToken(_rsTypeNames, TYPE_DECIMAL, ';'); + break; + case DataType::NUMERIC: + aName = o3tl::getToken(_rsTypeNames, TYPE_NUMERIC, ';'); + break; + case DataType::BIGINT: + aName = o3tl::getToken(_rsTypeNames, TYPE_BIGINT, ';'); + break; + case DataType::FLOAT: + aName = o3tl::getToken(_rsTypeNames, TYPE_FLOAT, ';'); + break; + case DataType::DOUBLE: + aName = o3tl::getToken(_rsTypeNames, TYPE_DOUBLE, ';'); + break; + case DataType::LONGVARCHAR: + aName = o3tl::getToken(_rsTypeNames, TYPE_MEMO, ';'); + break; + case DataType::LONGVARBINARY: + aName = o3tl::getToken(_rsTypeNames, TYPE_IMAGE, ';'); + break; + case DataType::DATE: + aName = o3tl::getToken(_rsTypeNames, TYPE_DATE, ';'); + break; + case DataType::TIME: + aName = o3tl::getToken(_rsTypeNames, TYPE_TIME, ';'); + break; + case DataType::TIMESTAMP: + aName = o3tl::getToken(_rsTypeNames, TYPE_DATETIME, ';'); + break; + case DataType::BIT: + if ( !pInfo->aCreateParams.isEmpty() ) + { + aName = o3tl::getToken(_rsTypeNames, TYPE_BIT, ';'); + break; + } + [[fallthrough]]; + case DataType::BOOLEAN: + aName = o3tl::getToken(_rsTypeNames, TYPE_BOOL, ';'); + break; + case DataType::TINYINT: + aName = o3tl::getToken(_rsTypeNames, TYPE_TINYINT, ';'); + break; + case DataType::SMALLINT: + aName = o3tl::getToken(_rsTypeNames, TYPE_SMALLINT, ';'); + break; + case DataType::INTEGER: + aName = o3tl::getToken(_rsTypeNames, TYPE_INTEGER, ';'); + break; + case DataType::REAL: + aName = o3tl::getToken(_rsTypeNames, TYPE_REAL, ';'); + break; + case DataType::BINARY: + aName = o3tl::getToken(_rsTypeNames, TYPE_BINARY, ';'); + break; + case DataType::VARBINARY: + aName = o3tl::getToken(_rsTypeNames, TYPE_VARBINARY, ';'); + break; + case DataType::SQLNULL: + aName = o3tl::getToken(_rsTypeNames, TYPE_SQLNULL, ';'); + break; + case DataType::OBJECT: + aName = o3tl::getToken(_rsTypeNames, TYPE_OBJECT, ';'); + break; + case DataType::DISTINCT: + aName = o3tl::getToken(_rsTypeNames, TYPE_DISTINCT, ';'); + break; + case DataType::STRUCT: + aName = o3tl::getToken(_rsTypeNames, TYPE_STRUCT, ';'); + break; + case DataType::ARRAY: + aName = o3tl::getToken(_rsTypeNames, TYPE_ARRAY, ';'); + break; + case DataType::BLOB: + aName = o3tl::getToken(_rsTypeNames, TYPE_BLOB, ';'); + break; + case DataType::CLOB: + aName = o3tl::getToken(_rsTypeNames, TYPE_CLOB, ';'); + break; + case DataType::REF: + aName = o3tl::getToken(_rsTypeNames, TYPE_REF, ';'); + break; + case DataType::OTHER: + aName = o3tl::getToken(_rsTypeNames, TYPE_OTHER, ';'); + break; + } + if ( !aName.empty() ) + { + pInfo->aUIName = aName; + pInfo->aUIName += " [ "; + } + pInfo->aUIName += pInfo->aTypeName; + if ( !aName.empty() ) + pInfo->aUIName += " ]"; + // Now that we have the type info, save it in the multimap + _rTypeInfoMap.emplace(pInfo->nType,pInfo); + } + // for a faster index access + _rTypeInfoIters.reserve(_rTypeInfoMap.size()); + + OTypeInfoMap::iterator aIter = _rTypeInfoMap.begin(); + OTypeInfoMap::const_iterator aEnd = _rTypeInfoMap.end(); + for(;aIter != aEnd;++aIter) + _rTypeInfoIters.push_back(aIter); + + // Close the result set/statement. + + ::comphelper::disposeComponent(xRs); +} + +void setColumnProperties(const Reference<XPropertySet>& _rxColumn,const OFieldDescription* _pFieldDesc) +{ + _rxColumn->setPropertyValue(PROPERTY_NAME,Any(_pFieldDesc->GetName())); + _rxColumn->setPropertyValue(PROPERTY_TYPENAME,Any(_pFieldDesc->getTypeInfo()->aTypeName)); + _rxColumn->setPropertyValue(PROPERTY_TYPE,Any(_pFieldDesc->GetType())); + _rxColumn->setPropertyValue(PROPERTY_PRECISION,Any(_pFieldDesc->GetPrecision())); + _rxColumn->setPropertyValue(PROPERTY_SCALE,Any(_pFieldDesc->GetScale())); + _rxColumn->setPropertyValue(PROPERTY_ISNULLABLE, Any(_pFieldDesc->GetIsNullable())); + _rxColumn->setPropertyValue(PROPERTY_ISAUTOINCREMENT, css::uno::Any(_pFieldDesc->IsAutoIncrement())); + _rxColumn->setPropertyValue(PROPERTY_DESCRIPTION,Any(_pFieldDesc->GetDescription())); + if ( _rxColumn->getPropertySetInfo()->hasPropertyByName(PROPERTY_ISCURRENCY) && _pFieldDesc->IsCurrency() ) + _rxColumn->setPropertyValue(PROPERTY_ISCURRENCY, css::uno::Any(_pFieldDesc->IsCurrency())); + // set autoincrement value when available + // and only set when the entry is not empty, that lets the value in the column untouched + if ( _pFieldDesc->IsAutoIncrement() && !_pFieldDesc->GetAutoIncrementValue().isEmpty() && _rxColumn->getPropertySetInfo()->hasPropertyByName(PROPERTY_AUTOINCREMENTCREATION) ) + _rxColumn->setPropertyValue(PROPERTY_AUTOINCREMENTCREATION,Any(_pFieldDesc->GetAutoIncrementValue())); +} + +OUString createDefaultName(const Reference< XDatabaseMetaData>& _xMetaData,const Reference<XNameAccess>& _xTables,const OUString& _sName) +{ + OSL_ENSURE(_xMetaData.is(),"No MetaData!"); + OUString sDefaultName = _sName; + try + { + OUString sCatalog,sSchema,sCompsedName; + if(_xMetaData->supportsCatalogsInTableDefinitions()) + { + try + { + Reference< XConnection> xCon = _xMetaData->getConnection(); + if ( xCon.is() ) + sCatalog = xCon->getCatalog(); + if ( sCatalog.isEmpty() ) + { + Reference<XResultSet> xRes = _xMetaData->getCatalogs(); + Reference<XRow> xRow(xRes,UNO_QUERY); + while(xRes.is() && xRes->next()) + { + sCatalog = xRow->getString(1); + if(!xRow->wasNull()) + break; + } + } + } + catch(const SQLException&) + { + } + } + if(_xMetaData->supportsSchemasInTableDefinitions()) + { + sSchema = _xMetaData->getUserName(); + } + sCompsedName = ::dbtools::composeTableName( _xMetaData, sCatalog, sSchema, _sName, false, ::dbtools::EComposeRule::InDataManipulation ); + sDefaultName = ::dbtools::createUniqueName(_xTables,sCompsedName); + } + catch(const SQLException&) + { + } + return sDefaultName; +} + +bool checkDataSourceAvailable(const OUString& _sDataSourceName,const Reference< css::uno::XComponentContext >& _xContext) +{ + Reference< XDatabaseContext > xDataBaseContext = DatabaseContext::create(_xContext); + bool bRet = xDataBaseContext->hasByName(_sDataSourceName); + if ( !bRet ) + { // try if this one is a URL + try + { + bRet = xDataBaseContext->getByName(_sDataSourceName).hasValue(); + } + catch(const Exception&) + { + } + } + return bRet; +} + +sal_Int32 mapTextAlign(const SvxCellHorJustify& _eAlignment) +{ + sal_Int32 nAlignment = css::awt::TextAlign::LEFT; + switch (_eAlignment) + { + case SvxCellHorJustify::Standard: + case SvxCellHorJustify::Left: nAlignment = css::awt::TextAlign::LEFT; break; + case SvxCellHorJustify::Center: nAlignment = css::awt::TextAlign::CENTER; break; + case SvxCellHorJustify::Right: nAlignment = css::awt::TextAlign::RIGHT; break; + default: + SAL_WARN("dbaccess.ui", "Invalid TextAlign!"); + } + return nAlignment; +} + +SvxCellHorJustify mapTextJustify(sal_Int32 _nAlignment) +{ + SvxCellHorJustify eJustify = SvxCellHorJustify::Left; + switch (_nAlignment) + { + case css::awt::TextAlign::LEFT : eJustify = SvxCellHorJustify::Left; break; + case css::awt::TextAlign::CENTER : eJustify = SvxCellHorJustify::Center; break; + case css::awt::TextAlign::RIGHT : eJustify = SvxCellHorJustify::Right; break; + default: + SAL_WARN("dbaccess.ui", "Invalid TextAlign!"); + } + return eJustify; +} + +void callColumnFormatDialog(const Reference<XPropertySet>& xAffectedCol, + const Reference<XPropertySet>& xField, + SvNumberFormatter* _pFormatter, + weld::Widget* _pParent) +{ + if (!(xAffectedCol.is() && xField.is())) + return; + + try + { + Reference< XPropertySetInfo > xInfo = xAffectedCol->getPropertySetInfo(); + bool bHasFormat = xInfo->hasPropertyByName(PROPERTY_FORMATKEY); + sal_Int32 nDataType = ::comphelper::getINT32(xField->getPropertyValue(PROPERTY_TYPE)); + + SvxCellHorJustify eJustify(SvxCellHorJustify::Standard); + Any aAlignment = xAffectedCol->getPropertyValue(PROPERTY_ALIGN); + if (aAlignment.hasValue()) + eJustify = dbaui::mapTextJustify(::comphelper::getINT16(aAlignment)); + sal_Int32 nFormatKey = 0; + if ( bHasFormat ) + nFormatKey = ::comphelper::getINT32(xAffectedCol->getPropertyValue(PROPERTY_FORMATKEY)); + + if(callColumnFormatDialog(_pParent,_pFormatter,nDataType,nFormatKey,eJustify,bHasFormat)) + { + xAffectedCol->setPropertyValue(PROPERTY_ALIGN, Any(static_cast<sal_Int16>(dbaui::mapTextAlign(eJustify)))); + if (bHasFormat) + xAffectedCol->setPropertyValue(PROPERTY_FORMATKEY, Any(nFormatKey)); + + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +bool callColumnFormatDialog(weld::Widget* _pParent, + SvNumberFormatter* _pFormatter, + sal_Int32 _nDataType, + sal_Int32& _nFormatKey, + SvxCellHorJustify& _eJustify, + bool _bHasFormat) +{ + bool bRet = false; + + // UNO->ItemSet + static SfxItemInfo aItemInfos[] = + { + { 0, false }, + { SID_ATTR_NUMBERFORMAT_VALUE, true }, + { SID_ATTR_ALIGN_HOR_JUSTIFY, true }, + { SID_ATTR_NUMBERFORMAT_INFO, true }, + { SID_ATTR_NUMBERFORMAT_ONE_AREA, true } + }; + static const auto aAttrMap = svl::Items< + SBA_DEF_RANGEFORMAT, SBA_ATTR_ALIGN_HOR_JUSTIFY, + SID_ATTR_NUMBERFORMAT_INFO, SID_ATTR_NUMBERFORMAT_INFO, + SID_ATTR_NUMBERFORMAT_ONE_AREA, SID_ATTR_NUMBERFORMAT_ONE_AREA + >; + + std::vector<SfxPoolItem*> pDefaults + { + new SfxRangeItem(SBA_DEF_RANGEFORMAT, SBA_DEF_FMTVALUE, SBA_ATTR_ALIGN_HOR_JUSTIFY), + new SfxUInt32Item(SBA_DEF_FMTVALUE), + new SvxHorJustifyItem(SvxCellHorJustify::Standard, SBA_ATTR_ALIGN_HOR_JUSTIFY), + new SvxNumberInfoItem(SID_ATTR_NUMBERFORMAT_INFO), + new SfxBoolItem(SID_ATTR_NUMBERFORMAT_ONE_AREA, false) + }; + + rtl::Reference<SfxItemPool> pPool(new SfxItemPool("GridBrowserProperties", SBA_DEF_RANGEFORMAT, SBA_ATTR_ALIGN_HOR_JUSTIFY, aItemInfos, &pDefaults)); + pPool->SetDefaultMetric( MapUnit::MapTwip ); // ripped, don't understand why + pPool->FreezeIdRanges(); // the same + + std::optional<SfxItemSet> pFormatDescriptor(SfxItemSet(*pPool, aAttrMap)); + // fill it + pFormatDescriptor->Put(SvxHorJustifyItem(_eJustify, SBA_ATTR_ALIGN_HOR_JUSTIFY)); + bool bText = false; + if (_bHasFormat) + { + // if the col is bound to a text field we have to disallow all non-text formats + if ((DataType::CHAR == _nDataType) || (DataType::VARCHAR == _nDataType) || (DataType::LONGVARCHAR == _nDataType) || (DataType::CLOB == _nDataType)) + { + bText = true; + pFormatDescriptor->Put(SfxBoolItem(SID_ATTR_NUMBERFORMAT_ONE_AREA, true)); + if (!_pFormatter->IsTextFormat(_nFormatKey)) + // text fields can only have text formats + _nFormatKey = _pFormatter->GetStandardFormat(SvNumFormatType::TEXT, Application::GetSettings().GetLanguageTag().getLanguageType()); + } + + pFormatDescriptor->Put(SfxUInt32Item(SBA_DEF_FMTVALUE, _nFormatKey)); + } + + if (!bText) + { + SvxNumberInfoItem aFormatter(_pFormatter, 1234.56789, SID_ATTR_NUMBERFORMAT_INFO); + pFormatDescriptor->Put(aFormatter); + } + + { // want the dialog to be destroyed before our set + SbaSbAttrDlg aDlg(_pParent, &*pFormatDescriptor, _pFormatter, _bHasFormat); + if (RET_OK == aDlg.run()) + { + // ItemSet->UNO + // UNO-properties + const SfxItemSet* pSet = aDlg.GetExampleSet(); + // (of course we could put the modified items directly into the column, but then the UNO-model + // won't reflect these changes, and why do we have a model, then ?) + + // horizontal justify + const SvxHorJustifyItem* pHorJustify = pSet->GetItem<SvxHorJustifyItem>(SBA_ATTR_ALIGN_HOR_JUSTIFY); + + _eJustify = pHorJustify->GetValue(); + + // format key + if (_bHasFormat) + { + const SfxUInt32Item* pFormat = pSet->GetItem<SfxUInt32Item>(SBA_DEF_FMTVALUE); + _nFormatKey = static_cast<sal_Int32>(pFormat->GetValue()); + } + bRet = true; + } + // deleted formats + const SfxItemSet* pResult = aDlg.GetOutputItemSet(); + if (pResult) + { + const SfxPoolItem* pItem = pResult->GetItem( SID_ATTR_NUMBERFORMAT_INFO ); + const SvxNumberInfoItem* pInfoItem = static_cast<const SvxNumberInfoItem*>(pItem); + if (pInfoItem) + { + for (sal_uInt32 key : pInfoItem->GetDelFormats()) + _pFormatter->DeleteEntry(key); + } + } + } + + pFormatDescriptor.reset(); + pPool.clear(); + for (SfxPoolItem* pDefault : pDefaults) + delete pDefault; + + return bRet; +} + +std::shared_ptr<const SfxFilter> getStandardDatabaseFilter() +{ + std::shared_ptr<const SfxFilter> pFilter = SfxFilter::GetFilterByName("StarOffice XML (Base)"); + OSL_ENSURE(pFilter,"Filter: StarOffice XML (Base) could not be found!"); + return pFilter; +} + +bool appendToFilter(const Reference<XConnection>& _xConnection, + const OUString& _sName, + const Reference< XComponentContext >& _rxContext, + weld::Window* pParent) +{ + bool bRet = false; + Reference< XChild> xChild(_xConnection,UNO_QUERY); + if(xChild.is()) + { + Reference< XPropertySet> xProp(xChild->getParent(),UNO_QUERY); + if(xProp.is()) + { + Sequence< OUString > aFilter; + xProp->getPropertyValue(PROPERTY_TABLEFILTER) >>= aFilter; + // first check if we have something like SCHEMA.% + bool bHasToInsert = true; + for (const OUString& rItem : std::as_const(aFilter)) + { + if(rItem.indexOf('%') != -1) + { + sal_Int32 nLen = rItem.lastIndexOf('.'); + if(nLen != -1 && !rItem.compareTo(_sName,nLen)) + bHasToInsert = false; + else if(rItem.getLength() == 1) + bHasToInsert = false; + } + } + + bRet = true; + if(bHasToInsert) + { + if(! ::dbaui::checkDataSourceAvailable(::comphelper::getString(xProp->getPropertyValue(PROPERTY_NAME)),_rxContext)) + { + OUString aMessage(DBA_RES(STR_TABLEDESIGN_DATASOURCE_DELETED)); + OSQLWarningBox aWarning(pParent, aMessage); + aWarning.run(); + bRet = false; + } + else + { + aFilter.realloc(aFilter.getLength()+1); + aFilter.getArray()[aFilter.getLength()-1] = _sName; + xProp->setPropertyValue(PROPERTY_TABLEFILTER,Any(aFilter)); + } + } + } + } + return bRet; +} + +void notifySystemWindow(vcl::Window const * _pWindow, vcl::Window* _pToRegister, const ::comphelper::mem_fun1_t<TaskPaneList,vcl::Window*>& _rMemFunc) +{ + OSL_ENSURE(_pWindow,"Window can not be null!"); + SystemWindow* pSystemWindow = _pWindow ? _pWindow->GetSystemWindow() : nullptr; + if ( pSystemWindow ) + { + _rMemFunc( pSystemWindow->GetTaskPaneList(), _pToRegister ); + } +} + +void adjustBrowseBoxColumnWidth( ::svt::EditBrowseBox* _pBox, sal_uInt16 _nColId ) +{ + sal_Int32 nColSize = -1; + sal_uInt32 nDefaultWidth = _pBox->GetDefaultColumnWidth( _pBox->GetColumnTitle( _nColId ) ); + if ( nDefaultWidth != _pBox->GetColumnWidth( _nColId ) ) + { + Size aSizeMM = _pBox->PixelToLogic( Size( _pBox->GetColumnWidth( _nColId ), 0 ), MapMode( MapUnit::MapMM ) ); + nColSize = aSizeMM.Width() * 10; + } + + Size aDefaultMM = _pBox->PixelToLogic( Size( nDefaultWidth, 0 ), MapMode( MapUnit::MapMM ) ); + + DlgSize aColumnSizeDlg(_pBox->GetFrameWeld(), nColSize, false, aDefaultMM.Width() * 10); + if (aColumnSizeDlg.run() != RET_OK) + return; + + sal_Int32 nValue = aColumnSizeDlg.GetValue(); + if ( -1 == nValue ) + { // default width + nValue = _pBox->GetDefaultColumnWidth( _pBox->GetColumnTitle( _nColId ) ); + } + else + { + Size aSizeMM( nValue / 10, 0 ); + nValue = _pBox->LogicToPixel( aSizeMM, MapMode( MapUnit::MapMM ) ).Width(); + } + _pBox->SetColumnWidth( _nColId, nValue ); +} + +// check if SQL92 name checking is enabled +bool isSQL92CheckEnabled(const Reference<XConnection>& _xConnection) +{ + return ::dbtools::getBooleanDataSourceSetting( _xConnection, PROPERTY_ENABLESQL92CHECK ); +} + +bool isAppendTableAliasEnabled(const Reference<XConnection>& _xConnection) +{ + return ::dbtools::getBooleanDataSourceSetting( _xConnection, INFO_APPEND_TABLE_ALIAS ); +} + +bool generateAsBeforeTableAlias(const Reference<XConnection>& _xConnection) +{ + return ::dbtools::getBooleanDataSourceSetting( _xConnection, INFO_AS_BEFORE_CORRELATION_NAME ); +} + +void fillAutoIncrementValue(const Reference<XPropertySet>& _xDatasource, + bool& _rAutoIncrementValueEnabled, + OUString& _rsAutoIncrementValue) +{ + if ( !_xDatasource.is() ) + return; + + OSL_ENSURE(_xDatasource->getPropertySetInfo()->hasPropertyByName(PROPERTY_INFO),"NO datasource supplied!"); + Sequence<PropertyValue> aInfo; + _xDatasource->getPropertyValue(PROPERTY_INFO) >>= aInfo; + + // search the right propertyvalue + const PropertyValue* pValue =std::find_if(std::cbegin(aInfo), std::cend(aInfo), + [](const PropertyValue& lhs) + {return lhs.Name == PROPERTY_AUTOINCREMENTCREATION;} ); + + if ( pValue != std::cend(aInfo) ) + pValue->Value >>= _rsAutoIncrementValue; + pValue =std::find_if(std::cbegin(aInfo), std::cend(aInfo), + [](const PropertyValue& lhs) + {return lhs.Name == "IsAutoRetrievingEnabled";} ); + + if ( pValue != std::cend(aInfo) ) + pValue->Value >>= _rAutoIncrementValueEnabled; +} + +void fillAutoIncrementValue(const Reference<XConnection>& _xConnection, + bool& _rAutoIncrementValueEnabled, + OUString& _rsAutoIncrementValue) +{ + Reference< XChild> xChild(_xConnection,UNO_QUERY); + if(xChild.is()) + { + Reference< XPropertySet> xProp(xChild->getParent(),UNO_QUERY); + fillAutoIncrementValue(xProp,_rAutoIncrementValueEnabled,_rsAutoIncrementValue); + } +} + +OUString getStrippedDatabaseName(const Reference<XPropertySet>& _xDataSource,OUString& _rsDatabaseName) +{ + if ( _rsDatabaseName.isEmpty() && _xDataSource.is() ) + { + try + { + _xDataSource->getPropertyValue(PROPERTY_NAME) >>= _rsDatabaseName; + } + catch(const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + OUString sName = _rsDatabaseName; + INetURLObject aURL(sName); + if ( aURL.GetProtocol() != INetProtocol::NotValid ) + sName = aURL.getBase(INetURLObject::LAST_SEGMENT,true,INetURLObject::DecodeMechanism::Unambiguous); + return sName; +} + +void setEvalDateFormatForFormatter(Reference< css::util::XNumberFormatter > const & _rxFormatter) +{ + OSL_ENSURE( _rxFormatter.is(),"setEvalDateFormatForFormatter: Formatter is NULL!"); + if ( !_rxFormatter.is() ) + return; + + Reference< css::util::XNumberFormatsSupplier > xSupplier = _rxFormatter->getNumberFormatsSupplier(); + + auto pSupplierImpl = comphelper::getFromUnoTunnel<SvNumberFormatsSupplierObj>(xSupplier); + OSL_ENSURE(pSupplierImpl,"No Supplier!"); + + if ( pSupplierImpl ) + { + SvNumberFormatter* pFormatter = pSupplierImpl->GetNumberFormatter(); + pFormatter->SetEvalDateFormat(NF_EVALDATEFORMAT_FORMAT); + } +} + +TOTypeInfoSP queryPrimaryKeyType(const OTypeInfoMap& _rTypeInfo) +{ + TOTypeInfoSP pTypeInfo; + // first we search for a type which supports autoIncrement + for (auto const& elem : _rTypeInfo) + { + // OJ: we don't want to set an autoincrement column to be key + // because we don't have the possibility to know how to create + // such auto increment column later on + // so until we know how to do it, we create a column without autoincrement + // therefore we have searched + if ( elem.second->nType == DataType::INTEGER ) + { + pTypeInfo = elem.second; // alternative + break; + } + else if ( !pTypeInfo && elem.second->nType == DataType::DOUBLE ) + pTypeInfo = elem.second; // alternative + else if ( !pTypeInfo && elem.second->nType == DataType::REAL ) + pTypeInfo = elem.second; // alternative + } + if ( !pTypeInfo ) // just a fallback + pTypeInfo = queryTypeInfoByType(DataType::VARCHAR,_rTypeInfo); + + OSL_ENSURE(pTypeInfo,"checkColumns: can't find a type which is usable as a key!"); + return pTypeInfo; +} + +TOTypeInfoSP queryTypeInfoByType(sal_Int32 _nDataType,const OTypeInfoMap& _rTypeInfo) +{ + OTypeInfoMap::const_iterator aIter = _rTypeInfo.find(_nDataType); + if(aIter != _rTypeInfo.end()) + return aIter->second; + // fall back if the type is unknown + TOTypeInfoSP pTypeInfo; + switch(_nDataType) + { + case DataType::TINYINT: + if( (pTypeInfo = queryTypeInfoByType(DataType::SMALLINT,_rTypeInfo) ) ) + break; + [[fallthrough]]; + case DataType::SMALLINT: + if( (pTypeInfo = queryTypeInfoByType(DataType::INTEGER,_rTypeInfo) ) ) + break; + [[fallthrough]]; + case DataType::INTEGER: + if( (pTypeInfo = queryTypeInfoByType(DataType::FLOAT,_rTypeInfo) ) ) + break; + [[fallthrough]]; + case DataType::FLOAT: + if( (pTypeInfo = queryTypeInfoByType(DataType::REAL,_rTypeInfo) ) ) + break; + [[fallthrough]]; + case DataType::DATE: + case DataType::TIME: + if( DataType::DATE == _nDataType || DataType::TIME == _nDataType ) + { + if( (pTypeInfo = queryTypeInfoByType(DataType::TIMESTAMP,_rTypeInfo) ) ) + break; + } + [[fallthrough]]; + case DataType::TIMESTAMP: + case DataType::REAL: + case DataType::BIGINT: + if ( (pTypeInfo = queryTypeInfoByType(DataType::DOUBLE,_rTypeInfo) ) ) + break; + [[fallthrough]]; + case DataType::DOUBLE: + if ( (pTypeInfo = queryTypeInfoByType(DataType::NUMERIC,_rTypeInfo) ) ) + break; + [[fallthrough]]; + case DataType::NUMERIC: + pTypeInfo = queryTypeInfoByType(DataType::DECIMAL,_rTypeInfo); + break; + case DataType::DECIMAL: + if ( (pTypeInfo = queryTypeInfoByType(DataType::NUMERIC,_rTypeInfo) ) ) + break; + if ( (pTypeInfo = queryTypeInfoByType(DataType::DOUBLE,_rTypeInfo) ) ) + break; + break; + case DataType::VARCHAR: + if ( (pTypeInfo = queryTypeInfoByType(DataType::LONGVARCHAR,_rTypeInfo) ) ) + break; + break; + case DataType::LONGVARCHAR: + if ( (pTypeInfo = queryTypeInfoByType(DataType::CLOB,_rTypeInfo) ) ) + break; + break; + default: + ; + } + if ( !pTypeInfo ) + { + bool bForce = true; + pTypeInfo = ::dbaui::getTypeInfoFromType(_rTypeInfo,DataType::VARCHAR,OUString(),"x",50,0,false,bForce); + } + OSL_ENSURE(pTypeInfo,"Wrong DataType supplied!"); + return pTypeInfo; +} + +sal_Int32 askForUserAction(weld::Window* pParent, TranslateId pTitle, TranslateId pText, bool _bAll, std::u16string_view _sName) +{ + SolarMutexGuard aGuard; + OUString aMsg = DBA_RES(pText); + aMsg = aMsg.replaceFirst("%1", _sName); + OSQLMessageBox aAsk(pParent, DBA_RES(pTitle), aMsg, MessBoxStyle::YesNo | MessBoxStyle::DefaultYes, MessageType::Query); + if ( _bAll ) + { + aAsk.add_button(DBA_RES(STR_BUTTON_TEXT_ALL), RET_ALL, HID_CONFIRM_DROP_BUTTON_ALL); + } + return aAsk.run(); +} + +namespace +{ + OUString lcl_createSDBCLevelStatement( const OUString& _rStatement, const Reference< XConnection >& _rxConnection ) + { + OUString sSDBCLevelStatement( _rStatement ); + try + { + Reference< XMultiServiceFactory > xAnalyzerFactory( _rxConnection, UNO_QUERY_THROW ); + Reference< XSingleSelectQueryAnalyzer > xAnalyzer( xAnalyzerFactory->createInstance( SERVICE_NAME_SINGLESELECTQUERYCOMPOSER ), UNO_QUERY_THROW ); + xAnalyzer->setQuery( _rStatement ); + sSDBCLevelStatement = xAnalyzer->getQueryWithSubstitution(); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + return sSDBCLevelStatement; + } +} + +Reference< XPropertySet > createView( const OUString& _rName, const Reference< XConnection >& _rxConnection, + const OUString& _rCommand ) +{ + Reference<XViewsSupplier> xSup(_rxConnection,UNO_QUERY); + Reference< XNameAccess > xViews; + if(xSup.is()) + xViews = xSup->getViews(); + Reference<XDataDescriptorFactory> xFact(xViews,UNO_QUERY); + OSL_ENSURE(xFact.is(),"No XDataDescriptorFactory available!"); + if(!xFact.is()) + return nullptr; + + Reference<XPropertySet> xView = xFact->createDataDescriptor(); + if ( !xView.is() ) + return nullptr; + + OUString sCatalog,sSchema,sTable; + ::dbtools::qualifiedNameComponents(_rxConnection->getMetaData(), + _rName, + sCatalog, + sSchema, + sTable, + ::dbtools::EComposeRule::InDataManipulation); + + xView->setPropertyValue(PROPERTY_CATALOGNAME,Any(sCatalog)); + xView->setPropertyValue(PROPERTY_SCHEMANAME,Any(sSchema)); + xView->setPropertyValue(PROPERTY_NAME,Any(sTable)); + + xView->setPropertyValue( PROPERTY_COMMAND, Any( _rCommand ) ); + + Reference<XAppend> xAppend(xViews,UNO_QUERY); + if(xAppend.is()) + xAppend->appendByDescriptor(xView); + + xView = nullptr; + // we need to reget the view because after appending it, it is no longer valid + // but this time it isn't a view object it is a table object with type "VIEW" + Reference<XTablesSupplier> xTabSup(_rxConnection,UNO_QUERY); + Reference< XNameAccess > xTables; + if ( xTabSup.is() ) + { + xTables = xTabSup->getTables(); + if ( xTables.is() && xTables->hasByName( _rName ) ) + xTables->getByName( _rName ) >>= xView; + } + + return xView; +} + +Reference<XPropertySet> createView( const OUString& _rName, const Reference< XConnection >& _rxConnection + ,const Reference<XPropertySet>& _rxSourceObject) +{ + OUString sCommand; + Reference< XPropertySetInfo > xPSI( _rxSourceObject->getPropertySetInfo(), UNO_SET_THROW ); + if ( xPSI->hasPropertyByName( PROPERTY_COMMAND ) ) + { + _rxSourceObject->getPropertyValue( PROPERTY_COMMAND ) >>= sCommand; + + bool bEscapeProcessing( false ); + OSL_VERIFY( _rxSourceObject->getPropertyValue( PROPERTY_ESCAPE_PROCESSING ) >>= bEscapeProcessing ); + if ( bEscapeProcessing ) + sCommand = lcl_createSDBCLevelStatement( sCommand, _rxConnection ); + } + else + { + sCommand = "SELECT * FROM " + composeTableNameForSelect( _rxConnection, _rxSourceObject ); + } + return createView( _rName, _rxConnection, sCommand ); +} + +bool insertHierarchyElement(weld::Window* pParent, const Reference< XComponentContext >& _rxContext, + const Reference<XHierarchicalNameContainer>& _xNames, + const OUString& _sParentFolder, + bool _bForm, + bool _bCollection, + const Reference<XContent>& _xContent, + bool _bMove) +{ + OSL_ENSURE( _xNames.is(), "insertHierarchyElement: illegal name container!" ); + if ( !_xNames.is() ) + return false; + + Reference<XNameAccess> xNameAccess( _xNames, UNO_QUERY ); + if ( _xNames->hasByHierarchicalName(_sParentFolder) ) + { + Reference<XChild> xChild(_xNames->getByHierarchicalName(_sParentFolder),UNO_QUERY); + xNameAccess.set(xChild,UNO_QUERY); + if ( !xNameAccess.is() && xChild.is() ) + xNameAccess.set(xChild->getParent(),UNO_QUERY); + } + + OSL_ENSURE( xNameAccess.is(), "insertHierarchyElement: could not find the proper name container!" ); + if ( !xNameAccess.is() ) + return false; + + OUString sNewName; + Reference<XPropertySet> xProp(_xContent,UNO_QUERY); + if ( xProp.is() ) + xProp->getPropertyValue(PROPERTY_NAME) >>= sNewName; + + if ( !_bMove || sNewName.isEmpty() ) + { + if ( sNewName.isEmpty() || xNameAccess->hasByName(sNewName) ) + { + OUString sLabel, sTargetName; + if ( !sNewName.isEmpty() ) + sTargetName = sNewName; + else + sTargetName = DBA_RES( _bCollection ? STR_NEW_FOLDER : ((_bForm) ? RID_STR_FORM : RID_STR_REPORT)); + sLabel = DBA_RES( _bCollection ? STR_FOLDER_LABEL : ((_bForm) ? STR_FRM_LABEL : STR_RPT_LABEL)); + sTargetName = ::dbtools::createUniqueName(xNameAccess,sTargetName); + + // here we have everything needed to create a new query object ... + HierarchicalNameCheck aNameChecker( _xNames, _sParentFolder ); + // ... ehm, except a new name + OSaveAsDlg aAskForName(pParent, + _rxContext, + sTargetName, + sLabel, + aNameChecker, + SADFlags::AdditionalDescription | SADFlags::TitlePasteAs); + if ( RET_OK != aAskForName.run() ) + // cancelled by the user + return false; + + sNewName = aAskForName.getName(); + } + } + else if ( xNameAccess->hasByName(sNewName) ) + { + OUString sError(DBA_RES(STR_NAME_ALREADY_EXISTS)); + sError = sError.replaceFirst("#",sNewName); + throw SQLException(sError,nullptr,"S1000",0,Any()); + } + + try + { + Reference<XMultiServiceFactory> xORB( xNameAccess, UNO_QUERY_THROW ); + uno::Sequence<uno::Any> aArguments(comphelper::InitAnyPropertySequence( + { + {"Name", uno::Any(sNewName)}, // set as folder + {"Parent", uno::Any(xNameAccess)}, + {PROPERTY_EMBEDDEDOBJECT, uno::Any(_xContent)}, + })); + OUString sServiceName(_bCollection ? (_bForm ? OUString(SERVICE_NAME_FORM_COLLECTION) : OUString(SERVICE_NAME_REPORT_COLLECTION)) : OUString(SERVICE_SDB_DOCUMENTDEFINITION)); + + Reference<XContent > xNew( xORB->createInstanceWithArguments( sServiceName, aArguments ), UNO_QUERY_THROW ); + Reference< XNameContainer > xNameContainer( xNameAccess, UNO_QUERY_THROW ); + xNameContainer->insertByName( sNewName, Any( xNew ) ); + } + catch( const IllegalArgumentException& e ) + { + ::dbtools::throwGenericSQLException( e.Message, e.Context ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + return false; + } + + return true; +} + +Reference< XNumberFormatter > getNumberFormatter(const Reference< XConnection >& _rxConnection, const Reference< css::uno::XComponentContext >& _rxContext ) +{ + // create a formatter working with the connections format supplier + Reference< XNumberFormatter > xFormatter; + + try + { + Reference< css::util::XNumberFormatsSupplier > xSupplier(::dbtools::getNumberFormats(_rxConnection, true, _rxContext)); + + if ( xSupplier.is() ) + { + // create a new formatter + xFormatter.set(util::NumberFormatter::create( _rxContext ), UNO_QUERY_THROW); + xFormatter->attachNumberFormatsSupplier(xSupplier); + } + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + return xFormatter; +} + +} // dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/misc/UpdateHelperImpl.hxx b/dbaccess/source/ui/misc/UpdateHelperImpl.hxx new file mode 100644 index 000000000..9f8d0d399 --- /dev/null +++ b/dbaccess/source/ui/misc/UpdateHelperImpl.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 . + */ +#pragma once + +#include <com/sun/star/sdbc/XParameters.hpp> +#include <com/sun/star/sdbc/XPreparedStatement.hpp> +#include <IUpdateHelper.hxx> + +namespace dbaui +{ + class OParameterUpdateHelper : public IUpdateHelper + { + css::uno::Reference< css::sdbc::XPreparedStatement > m_xPrepared; + css::uno::Reference< css::sdbc::XParameters > m_xParameters; + + public: + explicit OParameterUpdateHelper(const css::uno::Reference< css::sdbc::XPreparedStatement >& _xPrepared) + :m_xPrepared(_xPrepared) + ,m_xParameters(_xPrepared,css::uno::UNO_QUERY) + { + } + virtual ~OParameterUpdateHelper() {} + virtual void updateString(sal_Int32 _nPos, const OUString& _sValue) override + { + m_xParameters->setString(_nPos, _sValue); + } + virtual void updateDouble(sal_Int32 _nPos,const double& _nValue) override + { + m_xParameters->setDouble(_nPos, _nValue); + } + virtual void updateDate(sal_Int32 _nPos,const css::util::Date& _nValue) override + { + m_xParameters->setDate(_nPos, _nValue); + } + virtual void updateTime(sal_Int32 _nPos,const css::util::Time& _nValue) override + { + m_xParameters->setTime(_nPos, _nValue); + } + virtual void updateTimestamp(sal_Int32 _nPos,const css::util::DateTime& _nValue) override + { + m_xParameters->setTimestamp(_nPos, _nValue); + } + virtual void updateInt(sal_Int32 _nPos, sal_Int32 _nValue) override + { + m_xParameters->setInt(_nPos, _nValue); + } + virtual void updateNull(sal_Int32 _nPos, ::sal_Int32 sqlType) override + { + m_xParameters->setNull(_nPos,sqlType); + } + virtual void insertRow() override + { + m_xPrepared->executeUpdate(); + } + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/misc/WCPage.cxx b/dbaccess/source/ui/misc/WCPage.cxx new file mode 100644 index 000000000..602edd2d6 --- /dev/null +++ b/dbaccess/source/ui/misc/WCPage.cxx @@ -0,0 +1,325 @@ +/* -*- 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 <WCPage.hxx> +#include <WCopyTable.hxx> + +#include <defaultobjectnamecheck.hxx> +#include <strings.hrc> +#include <core_resource.hxx> +#include <com/sun/star/sdb/CommandType.hpp> +#include <com/sun/star/sdbcx/XTablesSupplier.hpp> +#include <com/sun/star/sdb/application/CopyTableOperation.hpp> +#include <connectivity/dbexception.hxx> +#include <connectivity/dbtools.hxx> + +using namespace ::dbaui; +using namespace ::dbtools; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::sdb; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::sdbcx; + +namespace CopyTableOperation = css::sdb::application::CopyTableOperation; + +OCopyTable::OCopyTable(weld::Container* pPage, OCopyTableWizard* pWizard) + : OWizardPage(pPage, pWizard, "dbaccess/ui/copytablepage.ui", "CopyTablePage") + , m_bPKeyAllowed(false) + , m_bUseHeaderAllowed(true) + , m_nOldOperation(0) + , m_xEdTableName(m_xBuilder->weld_entry("name")) + , m_xRB_DefData(m_xBuilder->weld_radio_button("defdata")) + , m_xRB_Def(m_xBuilder->weld_radio_button("def")) + , m_xRB_View(m_xBuilder->weld_radio_button("view")) + , m_xRB_AppendData(m_xBuilder->weld_radio_button("data")) + , m_xCB_UseHeaderLine(m_xBuilder->weld_check_button("firstline")) + , m_xCB_PrimaryColumn(m_xBuilder->weld_check_button("primarykey")) + , m_xFT_KeyName(m_xBuilder->weld_label("keynamelabel")) + , m_xEdKeyName(m_xBuilder->weld_entry("keyname")) +{ + if ( m_pParent->m_xDestConnection.is() ) + { + if (!m_pParent->supportsViews()) + m_xRB_View->set_sensitive(false); + + m_xCB_UseHeaderLine->set_active(true); + m_bPKeyAllowed = m_pParent->supportsPrimaryKey(); + + m_xCB_PrimaryColumn->set_sensitive(m_bPKeyAllowed); + + m_xRB_AppendData->connect_toggled( LINK( this, OCopyTable, RadioChangeHdl ) ); + m_xRB_DefData->connect_toggled( LINK( this, OCopyTable, RadioChangeHdl ) ); + m_xRB_Def->connect_toggled( LINK( this, OCopyTable, RadioChangeHdl ) ); + m_xRB_View->connect_toggled( LINK( this, OCopyTable, RadioChangeHdl ) ); + + m_xCB_PrimaryColumn->connect_toggled(LINK( this, OCopyTable, KeyClickHdl ) ); + + m_xFT_KeyName->set_sensitive(false); + m_xEdKeyName->set_sensitive(false); + m_xEdKeyName->set_text(m_pParent->createUniqueName("ID")); + + const sal_Int32 nMaxLen = m_pParent->getMaxColumnNameLength(); + m_xEdKeyName->set_max_length(nMaxLen); + } + + SetPageTitle(DBA_RES(STR_COPYTABLE_TITLE_COPY)); +} + +OCopyTable::~OCopyTable() +{ +} + +void OCopyTable::SetAppendDataRadio() +{ + m_pParent->EnableNextButton(true); + m_xFT_KeyName->set_sensitive(false); + m_xCB_PrimaryColumn->set_sensitive(false); + m_xEdKeyName->set_sensitive(false); + m_pParent->setOperation(CopyTableOperation::AppendData); +} + +IMPL_LINK(OCopyTable, RadioChangeHdl, weld::Toggleable&, rButton, void) +{ + if (!rButton.get_active()) + return; + if (m_xRB_AppendData->get_active()) + { + SetAppendDataRadio(); + return; + } + m_pParent->EnableNextButton(!m_xRB_View->get_active()); + bool bKey = m_bPKeyAllowed && !m_xRB_View->get_active(); + m_xFT_KeyName->set_sensitive(bKey && m_xCB_PrimaryColumn->get_active()); + m_xEdKeyName->set_sensitive(bKey && m_xCB_PrimaryColumn->get_active()); + m_xCB_PrimaryColumn->set_sensitive(bKey); + m_xCB_UseHeaderLine->set_sensitive(m_bUseHeaderAllowed && IsOptionDefData()); + + // set type what to do + if( IsOptionDefData() ) + m_pParent->setOperation( CopyTableOperation::CopyDefinitionAndData ); + else if( IsOptionDef() ) + m_pParent->setOperation( CopyTableOperation::CopyDefinitionOnly ); + else if( IsOptionView() ) + m_pParent->setOperation( CopyTableOperation::CreateAsView ); +} + +IMPL_LINK_NOARG( OCopyTable, KeyClickHdl, weld::Toggleable&, void ) +{ + m_xEdKeyName->set_sensitive(m_xCB_PrimaryColumn->get_active()); + m_xFT_KeyName->set_sensitive(m_xCB_PrimaryColumn->get_active()); +} + +bool OCopyTable::LeavePage() +{ + m_pParent->m_bCreatePrimaryKeyColumn = m_bPKeyAllowed && m_xCB_PrimaryColumn->get_sensitive() && m_xCB_PrimaryColumn->get_active(); + m_pParent->m_aKeyName = m_pParent->m_bCreatePrimaryKeyColumn ? m_xEdKeyName->get_text() : OUString(); + m_pParent->setUseHeaderLine( m_xCB_UseHeaderLine->get_active() ); + + // first check if the table already exists in the database + if( m_pParent->getOperation() != CopyTableOperation::AppendData ) + { + m_pParent->clearDestColumns(); + DynamicTableOrQueryNameCheck aNameCheck( m_pParent->m_xDestConnection, CommandType::TABLE ); + SQLExceptionInfo aErrorInfo; + if ( !aNameCheck.isNameValid( m_xEdTableName->get_text(), aErrorInfo ) ) + { + aErrorInfo.append( SQLExceptionInfo::TYPE::SQLContext, DBA_RES( STR_SUGGEST_APPEND_TABLE_DATA ) ); + m_pParent->showError(aErrorInfo.get()); + + return false; + } + + // have to check the length of the table name + Reference< XDatabaseMetaData > xMeta = m_pParent->m_xDestConnection->getMetaData(); + OUString sCatalog; + OUString sSchema; + OUString sTable; + ::dbtools::qualifiedNameComponents( xMeta, + m_xEdTableName->get_text(), + sCatalog, + sSchema, + sTable, + ::dbtools::EComposeRule::InDataManipulation); + sal_Int32 nMaxLength = xMeta->getMaxTableNameLength(); + if ( nMaxLength && sTable.getLength() > nMaxLength ) + { + m_pParent->showError(DBA_RES(STR_INVALID_TABLE_NAME_LENGTH)); + return false; + } + + // now we have to check if the name of the primary key already exists + if ( m_pParent->m_bCreatePrimaryKeyColumn + && m_pParent->m_aKeyName != m_pParent->createUniqueName(m_pParent->m_aKeyName) ) + { + m_pParent->showError(DBA_RES(STR_WIZ_NAME_ALREADY_DEFINED) + " " + m_pParent->m_aKeyName); + return false; + } + } + + if (m_xEdTableName->get_value_changed_from_saved()) + { // table exists and name has changed + if ( m_pParent->getOperation() == CopyTableOperation::AppendData ) + { + if(!checkAppendData()) + return false; + } + else if ( m_nOldOperation == CopyTableOperation::AppendData ) + { + m_xEdTableName->save_value(); + return LeavePage(); + } + } + else + { // table exist and is not new or doesn't exist and so on + if ( CopyTableOperation::AppendData == m_pParent->getOperation() ) + { + if( !checkAppendData() ) + return false; + } + } + m_pParent->m_sName = m_xEdTableName->get_text(); + m_xEdTableName->save_value(); + + if(m_pParent->m_sName.isEmpty()) + { + m_pParent->showError(DBA_RES(STR_INVALID_TABLE_NAME)); + return false; + } + + return true; +} + +void OCopyTable::Activate() +{ + m_pParent->GetOKButton().set_sensitive(true); + m_nOldOperation = m_pParent->getOperation(); + m_xEdTableName->grab_focus(); + m_xCB_UseHeaderLine->set_active(m_pParent->UseHeaderLine()); +} + +OUString OCopyTable::GetTitle() const +{ + return DBA_RES(STR_WIZ_TABLE_COPY); +} + +void OCopyTable::Reset() +{ + m_bFirstTime = false; + + m_xEdTableName->set_text( m_pParent->m_sName ); + m_xEdTableName->save_value(); +} + +bool OCopyTable::checkAppendData() +{ + m_pParent->clearDestColumns(); + Reference< XPropertySet > xTable; + Reference< XTablesSupplier > xSup( m_pParent->m_xDestConnection, UNO_QUERY ); + Reference<XNameAccess> xTables; + if (xSup.is()) + xTables = xSup->getTables(); + if (xTables.is() && xTables->hasByName(m_xEdTableName->get_text())) + { + const ODatabaseExport::TColumnVector& rSrcColumns = m_pParent->getSrcVector(); + const sal_uInt32 nSrcSize = rSrcColumns.size(); + m_pParent->m_vColumnPositions.resize( nSrcSize, ODatabaseExport::TPositions::value_type( COLUMN_POSITION_NOT_FOUND, COLUMN_POSITION_NOT_FOUND ) ); + m_pParent->m_vColumnTypes.resize( nSrcSize , COLUMN_POSITION_NOT_FOUND ); + + // set new destination + xTables->getByName( m_xEdTableName->get_text() ) >>= xTable; + ObjectCopySource aTableCopySource( m_pParent->m_xDestConnection, xTable ); + m_pParent->loadData( aTableCopySource, m_pParent->m_vDestColumns, m_pParent->m_aDestVec ); + const ODatabaseExport::TColumnVector& rDestColumns = m_pParent->getDestVector(); + const sal_uInt32 nMinSrcDestSize = std::min<sal_uInt32>(nSrcSize, rDestColumns.size()); + sal_uInt32 i = 0; + for (auto const& column : rDestColumns) + { + if (i >= nMinSrcDestSize) + break; + bool bNotConvert = true; + m_pParent->m_vColumnPositions[i] = ODatabaseExport::TPositions::value_type(i+1,i+1); + TOTypeInfoSP pTypeInfo = m_pParent->convertType(column->second->getSpecialTypeInfo(),bNotConvert); + if ( !bNotConvert ) + { + m_pParent->showColumnTypeNotSupported(column->first); + return false; + } + + if ( pTypeInfo ) + m_pParent->m_vColumnTypes[i] = pTypeInfo->nType; + else + m_pParent->m_vColumnTypes[i] = DataType::VARCHAR; + ++i; + } + + } + + if ( !xTable.is() ) + { + m_pParent->showError(DBA_RES(STR_INVALID_TABLE_NAME)); + return false; + } + return true; +} + +void OCopyTable::setCreatePrimaryKey( bool _bDoCreate, const OUString& _rSuggestedName ) +{ + bool bCreatePK = m_bPKeyAllowed && _bDoCreate; + m_xCB_PrimaryColumn->set_active( bCreatePK ); + m_xEdKeyName->set_text( _rSuggestedName ); + + m_xFT_KeyName->set_sensitive( bCreatePK ); + m_xEdKeyName->set_sensitive( bCreatePK ); +} + +void OCopyTable::setCreateStyleAction() +{ + // reselect the last action before + switch (m_pParent->getOperation()) + { + case CopyTableOperation::CopyDefinitionAndData: + m_xRB_DefData->set_active(true); + RadioChangeHdl(*m_xRB_DefData); + break; + case CopyTableOperation::CopyDefinitionOnly: + m_xRB_Def->set_active(true); + RadioChangeHdl(*m_xRB_Def); + break; + case CopyTableOperation::AppendData: + m_xRB_AppendData->set_active(true); + SetAppendDataRadio(); + break; + case CopyTableOperation::CreateAsView: + if (m_xRB_View->get_sensitive()) + { + m_xRB_View->set_active(true); + RadioChangeHdl(*m_xRB_View); + } + else + { + m_xRB_DefData->set_active(true); + RadioChangeHdl(*m_xRB_DefData); + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/misc/WColumnSelect.cxx b/dbaccess/source/ui/misc/WColumnSelect.cxx new file mode 100644 index 000000000..8937cfb2d --- /dev/null +++ b/dbaccess/source/ui/misc/WColumnSelect.cxx @@ -0,0 +1,403 @@ +/* -*- 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 <WColumnSelect.hxx> +#include <strings.hrc> +#include <osl/diagnose.h> +#include <WCopyTable.hxx> +#include <com/sun/star/sdbcx/XColumnsSupplier.hpp> +#include <core_resource.hxx> +#include <com/sun/star/sdb/application/CopyTableOperation.hpp> + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::sdbcx; +using namespace dbaui; + +namespace CopyTableOperation = ::com::sun::star::sdb::application::CopyTableOperation; + +OUString OWizColumnSelect::GetTitle() const { return DBA_RES(STR_WIZ_COLUMN_SELECT_TITLE); } + +OWizardPage::OWizardPage(weld::Container* pPage, OCopyTableWizard* pWizard, const OUString& rUIXMLDescription, const OString& rID) + : ::vcl::OWizardPage(pPage, pWizard, rUIXMLDescription, rID) + , m_pParent(pWizard) + , m_bFirstTime(true) +{ +} + +OWizardPage::~OWizardPage() +{ +} + +// OWizColumnSelect +OWizColumnSelect::OWizColumnSelect(weld::Container* pPage, OCopyTableWizard* pWizard) + : OWizardPage(pPage, pWizard, "dbaccess/ui/applycolpage.ui", "ApplyColPage") + , m_xOrgColumnNames(m_xBuilder->weld_tree_view("from")) + , m_xColumn_RH(m_xBuilder->weld_button("colrh")) + , m_xColumns_RH(m_xBuilder->weld_button("colsrh")) + , m_xColumn_LH(m_xBuilder->weld_button("collh")) + , m_xColumns_LH(m_xBuilder->weld_button("colslh")) + , m_xNewColumnNames(m_xBuilder->weld_tree_view("to")) +{ + m_xColumn_RH->connect_clicked(LINK(this,OWizColumnSelect,ButtonClickHdl)); + m_xColumn_LH->connect_clicked(LINK(this,OWizColumnSelect,ButtonClickHdl)); + m_xColumns_RH->connect_clicked(LINK(this,OWizColumnSelect,ButtonClickHdl)); + m_xColumns_LH->connect_clicked(LINK(this,OWizColumnSelect,ButtonClickHdl)); + + m_xOrgColumnNames->set_selection_mode(SelectionMode::Multiple); + m_xNewColumnNames->set_selection_mode(SelectionMode::Multiple); + + m_xOrgColumnNames->connect_row_activated(LINK(this,OWizColumnSelect,ListDoubleClickHdl)); + m_xNewColumnNames->connect_row_activated(LINK(this,OWizColumnSelect,ListDoubleClickHdl)); +} + +OWizColumnSelect::~OWizColumnSelect() +{ + while (m_xNewColumnNames->n_children()) + { + delete weld::fromId<OFieldDescription*>(m_xNewColumnNames->get_id(0)); + m_xNewColumnNames->remove(0); + } +} + +void OWizColumnSelect::Reset() +{ + // restore original state + clearListBox(*m_xOrgColumnNames); + clearListBox(*m_xNewColumnNames); + m_pParent->m_mNameMapping.clear(); + + // insert the source columns in the left listbox + const ODatabaseExport::TColumnVector& rSrcColumns = m_pParent->getSrcVector(); + + for (auto const& column : rSrcColumns) + { + OUString sId(weld::toId(column->second)); + m_xOrgColumnNames->append(sId, column->first); + } + + if (m_xOrgColumnNames->n_children()) + m_xOrgColumnNames->select(0); + + m_bFirstTime = false; +} + +void OWizColumnSelect::Activate( ) +{ + // if there are no dest columns reset the left side with the original columns + if(m_pParent->getDestColumns().empty()) + Reset(); + + clearListBox(*m_xNewColumnNames); + + const ODatabaseExport::TColumnVector& rDestColumns = m_pParent->getDestVector(); + + // tdf#113923, the added columns must exist in the table + // in the case where: + // 1: we enabled the creation of a primary key + // 2: we come back here from the "Back" button of the next page, + // we want to avoid to list the new column generated in the next page + const ODatabaseExport::TColumns& rSrcColumns = m_pParent->getSourceColumns(); + + for (auto const& column : rDestColumns) + { + if (rSrcColumns.find(column->first) != rSrcColumns.end()) + { + OUString sId(weld::toId(new OFieldDescription(*(column->second)))); + m_xNewColumnNames->append(sId, column->first); + int nRemove = m_xOrgColumnNames->find_text(column->first); + if (nRemove != -1) + m_xOrgColumnNames->remove(nRemove); + } + } + m_pParent->GetOKButton().set_sensitive(m_xNewColumnNames->n_children() != 0); + m_pParent->EnableNextButton(m_xNewColumnNames->n_children() && m_pParent->getOperation() != CopyTableOperation::AppendData); + m_xColumns_RH->grab_focus(); +} + +bool OWizColumnSelect::LeavePage() +{ + + m_pParent->clearDestColumns(); + + for(sal_Int32 i=0 ; i< m_xNewColumnNames->n_children();++i) + { + OFieldDescription* pField = weld::fromId<OFieldDescription*>(m_xNewColumnNames->get_id(i)); + OSL_ENSURE(pField,"The field information can not be null!"); + m_pParent->insertColumn(i,pField); + } + + clearListBox(*m_xNewColumnNames); + + if ( m_pParent->GetPressedButton() == OCopyTableWizard::WIZARD_NEXT + || m_pParent->GetPressedButton() == OCopyTableWizard::WIZARD_FINISH + ) + return !m_pParent->getDestColumns().empty(); + else + return true; +} + +IMPL_LINK(OWizColumnSelect, ButtonClickHdl, weld::Button&, rButton, void) +{ + weld::TreeView *pLeft = nullptr; + weld::TreeView *pRight = nullptr; + bool bAll = false; + + if (&rButton == m_xColumn_RH.get()) + { + pLeft = m_xOrgColumnNames.get(); + pRight = m_xNewColumnNames.get(); + } + else if (&rButton == m_xColumn_LH.get()) + { + pLeft = m_xNewColumnNames.get(); + pRight = m_xOrgColumnNames.get(); + } + else if (&rButton == m_xColumns_RH.get()) + { + pLeft = m_xOrgColumnNames.get(); + pRight = m_xNewColumnNames.get(); + bAll = true; + } + else if (&rButton == m_xColumns_LH.get()) + { + pLeft = m_xNewColumnNames.get(); + pRight = m_xOrgColumnNames.get(); + bAll = true; + } + + if (!pLeft || !pRight) + return; + + Reference< XDatabaseMetaData > xMetaData( m_pParent->m_xDestConnection->getMetaData() ); + OUString sExtraChars = xMetaData->getExtraNameCharacters(); + sal_Int32 nMaxNameLen = m_pParent->getMaxColumnNameLength(); + + ::comphelper::UStringMixEqual aCase(xMetaData->supportsMixedCaseQuotedIdentifiers()); + std::vector< OUString> aRightColumns; + fillColumns(pRight,aRightColumns); + + if(!bAll) + { + auto aRows = pLeft->get_selected_rows(); + std::sort(aRows.begin(), aRows.end()); + + for (auto it = aRows.begin(); it != aRows.end(); ++it) + moveColumn(pRight,pLeft,aRightColumns,pLeft->get_text(*it),sExtraChars,nMaxNameLen,aCase); + + for (auto it = aRows.rbegin(); it != aRows.rend(); ++it) + pLeft->remove(*it); + } + else + { + const sal_Int32 nEntries = pLeft->n_children(); + for(sal_Int32 i=0; i < nEntries; ++i) + moveColumn(pRight,pLeft,aRightColumns,pLeft->get_text(i),sExtraChars,nMaxNameLen,aCase); + for(sal_Int32 j=pLeft->n_children(); j ; ) + pLeft->remove(--j); + } + + enableButtons(); + + if (m_xOrgColumnNames->n_children()) + m_xOrgColumnNames->select(0); +} + +IMPL_LINK( OWizColumnSelect, ListDoubleClickHdl, weld::TreeView&, rListBox, bool ) +{ + weld::TreeView *pLeft,*pRight; + if (&rListBox == m_xOrgColumnNames.get()) + { + pLeft = m_xOrgColumnNames.get(); + pRight = m_xNewColumnNames.get(); + } + else + { + pRight = m_xOrgColumnNames.get(); + pLeft = m_xNewColumnNames.get(); + } + + // If database is able to process PrimaryKeys, set PrimaryKey + Reference< XDatabaseMetaData > xMetaData( m_pParent->m_xDestConnection->getMetaData() ); + OUString sExtraChars = xMetaData->getExtraNameCharacters(); + sal_Int32 nMaxNameLen = m_pParent->getMaxColumnNameLength(); + + ::comphelper::UStringMixEqual aCase(xMetaData->supportsMixedCaseQuotedIdentifiers()); + std::vector< OUString> aRightColumns; + fillColumns(pRight,aRightColumns); + + auto aRows = pLeft->get_selected_rows(); + std::sort(aRows.begin(), aRows.end()); + + for (auto it = aRows.begin(); it != aRows.end(); ++it) + moveColumn(pRight,pLeft,aRightColumns,pLeft->get_text(*it),sExtraChars,nMaxNameLen,aCase); + + for (auto it = aRows.rbegin(); it != aRows.rend(); ++it) + pLeft->remove(*it); + + enableButtons(); + + return true; +} + +void OWizColumnSelect::clearListBox(weld::TreeView& rListBox) +{ + rListBox.clear(); +} + +void OWizColumnSelect::fillColumns(weld::TreeView const * pRight,std::vector< OUString> &_rRightColumns) +{ + const sal_Int32 nCount = pRight->n_children(); + _rRightColumns.reserve(nCount); + for (sal_Int32 i=0; i < nCount; ++i) + _rRightColumns.push_back(pRight->get_text(i)); +} + +void OWizColumnSelect::createNewColumn( weld::TreeView* _pListbox, + OFieldDescription const * _pSrcField, + std::vector< OUString>& _rRightColumns, + const OUString& _sColumnName, + std::u16string_view _sExtraChars, + sal_Int32 _nMaxNameLen, + const ::comphelper::UStringMixEqual& _aCase) +{ + OUString sConvertedName = m_pParent->convertColumnName(TMultiListBoxEntryFindFunctor(&_rRightColumns,_aCase), + _sColumnName, + _sExtraChars, + _nMaxNameLen); + OFieldDescription* pNewField = new OFieldDescription(*_pSrcField); + pNewField->SetName(sConvertedName); + bool bNotConvert = true; + pNewField->SetType(m_pParent->convertType(_pSrcField->getSpecialTypeInfo(),bNotConvert)); + if ( !m_pParent->supportsPrimaryKey() ) + pNewField->SetPrimaryKey(false); + + _pListbox->append(weld::toId(pNewField), sConvertedName); + _rRightColumns.push_back(sConvertedName); + + if ( !bNotConvert ) + m_pParent->showColumnTypeNotSupported(sConvertedName); +} + +void OWizColumnSelect::moveColumn( weld::TreeView* _pRight, + weld::TreeView const * _pLeft, + std::vector< OUString>& _rRightColumns, + const OUString& _sColumnName, + std::u16string_view _sExtraChars, + sal_Int32 _nMaxNameLen, + const ::comphelper::UStringMixEqual& _aCase) +{ + if(_pRight == m_xNewColumnNames.get()) + { + // we copy the column into the new format for the dest + OFieldDescription* pSrcField = weld::fromId<OFieldDescription*>(_pLeft->get_id(_pLeft->find_text(_sColumnName))); + createNewColumn(_pRight,pSrcField,_rRightColumns,_sColumnName,_sExtraChars,_nMaxNameLen,_aCase); + } + else + { + // find the new column in the dest name mapping to obtain the old column + OCopyTableWizard::TNameMapping::const_iterator aIter = std::find_if(m_pParent->m_mNameMapping.begin(),m_pParent->m_mNameMapping.end(), + [&_aCase, &_sColumnName] (const OCopyTableWizard::TNameMapping::value_type& nameMap) { + return _aCase(nameMap.second, _sColumnName); + }); + + OSL_ENSURE(aIter != m_pParent->m_mNameMapping.end(),"Column must be defined"); + if ( aIter == m_pParent->m_mNameMapping.end() ) + return; // do nothing + const ODatabaseExport::TColumns& rSrcColumns = m_pParent->getSourceColumns(); + ODatabaseExport::TColumns::const_iterator aSrcIter = rSrcColumns.find((*aIter).first); + if ( aSrcIter != rSrcColumns.end() ) + { + // we need also the old position of this column to insert it back on that position again + const ODatabaseExport::TColumnVector& rSrcVector = m_pParent->getSrcVector(); + ODatabaseExport::TColumnVector::const_iterator aPos = std::find(rSrcVector.begin(), rSrcVector.end(), aSrcIter); + OSL_ENSURE( aPos != rSrcVector.end(),"Invalid position for the iterator here!"); + ODatabaseExport::TColumnVector::size_type nPos = (aPos - rSrcVector.begin()) - adjustColumnPosition(_pLeft, _sColumnName, (aPos - rSrcVector.begin()), _aCase); + + OUString sId(weld::toId(aSrcIter->second)); + const OUString& rStr = (*aIter).first; + _pRight->insert(nullptr, nPos, &rStr, &sId, nullptr, nullptr, false, nullptr); + _rRightColumns.push_back(rStr); + m_pParent->removeColumnNameFromNameMap(_sColumnName); + } + } +} + +// Simply returning fields back to their original position is +// not enough. We need to take into account what fields have +// been removed earlier and adjust accordingly. Based on the +// algorithm employed in moveColumn(). +sal_Int32 OWizColumnSelect::adjustColumnPosition(weld::TreeView const * _pLeft, + std::u16string_view _sColumnName, + ODatabaseExport::TColumnVector::size_type nCurrentPos, + const ::comphelper::UStringMixEqual& _aCase) +{ + sal_Int32 nAdjustedPos = 0; + + // if returning all entries to their original position, + // then there is no need to adjust the positions. + if (m_xColumns_LH->has_focus()) + return nAdjustedPos; + + const sal_Int32 nCount = _pLeft->n_children(); + OUString sColumnString; + for(sal_Int32 i=0; i < nCount; ++i) + { + sColumnString = _pLeft->get_text(i); + if(_sColumnName != sColumnString) + { + // find the new column in the dest name mapping to obtain the old column + OCopyTableWizard::TNameMapping::const_iterator aIter = std::find_if(m_pParent->m_mNameMapping.begin(),m_pParent->m_mNameMapping.end(), + [&_aCase, &sColumnString] (const OCopyTableWizard::TNameMapping::value_type& nameMap) { + return _aCase(nameMap.second, sColumnString); + }); + + OSL_ENSURE(aIter != m_pParent->m_mNameMapping.end(),"Column must be defined"); + const ODatabaseExport::TColumns& rSrcColumns = m_pParent->getSourceColumns(); + ODatabaseExport::TColumns::const_iterator aSrcIter = rSrcColumns.find((*aIter).first); + if ( aSrcIter != rSrcColumns.end() ) + { + // we need also the old position of this column to insert it back on that position again + const ODatabaseExport::TColumnVector& rSrcVector = m_pParent->getSrcVector(); + ODatabaseExport::TColumnVector::const_iterator aPos = std::find(rSrcVector.begin(), rSrcVector.end(), aSrcIter); + ODatabaseExport::TColumnVector::size_type nPos = aPos - rSrcVector.begin(); + if( nPos < nCurrentPos) + { + nAdjustedPos++; + } + } + } + } + + return nAdjustedPos; +} + +void OWizColumnSelect::enableButtons() +{ + bool bEntries = m_xNewColumnNames->n_children() != 0; + if (!bEntries) + m_pParent->m_mNameMapping.clear(); + + m_pParent->GetOKButton().set_sensitive(bEntries); + m_pParent->EnableNextButton(bEntries && m_pParent->getOperation() != CopyTableOperation::AppendData); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/misc/WCopyTable.cxx b/dbaccess/source/ui/misc/WCopyTable.cxx new file mode 100644 index 000000000..64301bccd --- /dev/null +++ b/dbaccess/source/ui/misc/WCopyTable.cxx @@ -0,0 +1,1554 @@ +/* -*- 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 <strings.hrc> +#include <strings.hxx> +#include <core_resource.hxx> +#include <sqlmessage.hxx> +#include <UITools.hxx> +#include <WColumnSelect.hxx> +#include <WCopyTable.hxx> +#include <WCPage.hxx> +#include <WExtendPages.hxx> +#include <WNameMatch.hxx> +#include <WTypeSelect.hxx> + +#include <com/sun/star/sdb/application/CopyTableOperation.hpp> +#include <com/sun/star/sdb/SQLContext.hpp> +#include <com/sun/star/sdbc/ColumnValue.hpp> +#include <com/sun/star/sdbc/DataType.hpp> +#include <com/sun/star/sdbc/XResultSet.hpp> +#include <com/sun/star/sdbc/XStatement.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbcx/KeyType.hpp> +#include <com/sun/star/sdbcx/XAppend.hpp> +#include <com/sun/star/sdbcx/XColumnsSupplier.hpp> +#include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp> +#include <com/sun/star/sdbcx/XKeysSupplier.hpp> +#include <com/sun/star/sdbcx/XTablesSupplier.hpp> +#include <com/sun/star/sdbcx/XViewsSupplier.hpp> +#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp> +#include <com/sun/star/task/InteractionHandler.hpp> + +#include <comphelper/interaction.hxx> +#include <connectivity/dbtools.hxx> +#include <connectivity/dbmetadata.hxx> +#include <connectivity/dbexception.hxx> +#include <o3tl/safeint.hxx> +#include <rtl/ustrbuf.hxx> +#include <sal/log.hxx> +#include <tools/diagnose_ex.h> + +#include <algorithm> + +using namespace ::dbaui; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::sdb; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::task; +using namespace dbtools; + +namespace CopyTableOperation = ::com::sun::star::sdb::application::CopyTableOperation; + +#define MAX_PAGES 4 // max. number of pages, which are shown + +namespace +{ + void clearColumns(ODatabaseExport::TColumns& _rColumns, ODatabaseExport::TColumnVector& _rColumnsVec) + { + for (auto const& column : _rColumns) + delete column.second; + + _rColumnsVec.clear(); + _rColumns.clear(); + } +} + +// ICopyTableSourceObject +ICopyTableSourceObject::~ICopyTableSourceObject() +{ +} + +// ObjectCopySource +ObjectCopySource::ObjectCopySource( const Reference< XConnection >& _rxConnection, const Reference< XPropertySet >& _rxObject ) + :m_xConnection( _rxConnection, UNO_SET_THROW ) + ,m_xMetaData( _rxConnection->getMetaData(), UNO_SET_THROW ) + ,m_xObject( _rxObject, UNO_SET_THROW ) + ,m_xObjectPSI( _rxObject->getPropertySetInfo(), UNO_SET_THROW ) + ,m_xObjectColumns( Reference< XColumnsSupplier >( _rxObject, UNO_QUERY_THROW )->getColumns(), UNO_SET_THROW ) +{ +} + +OUString ObjectCopySource::getQualifiedObjectName() const +{ + OUString sName; + + if ( !m_xObjectPSI->hasPropertyByName( PROPERTY_COMMAND ) ) + sName = ::dbtools::composeTableName( m_xMetaData, m_xObject, ::dbtools::EComposeRule::InDataManipulation, false ); + else + m_xObject->getPropertyValue( PROPERTY_NAME ) >>= sName; + return sName; +} + +bool ObjectCopySource::isView() const +{ + bool bIsView = false; + try + { + if ( m_xObjectPSI->hasPropertyByName( PROPERTY_TYPE ) ) + { + OUString sObjectType; + OSL_VERIFY( m_xObject->getPropertyValue( PROPERTY_TYPE ) >>= sObjectType ); + bIsView = sObjectType == "VIEW"; + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + return bIsView; +} + +void ObjectCopySource::copyUISettingsTo( const Reference< XPropertySet >& _rxObject ) const +{ + const OUString aCopyProperties[] = { + OUString(PROPERTY_FONT), OUString(PROPERTY_ROW_HEIGHT), OUString(PROPERTY_TEXTCOLOR),OUString(PROPERTY_TEXTLINECOLOR),OUString(PROPERTY_TEXTEMPHASIS),OUString(PROPERTY_TEXTRELIEF) + }; + for (const auto & aCopyProperty : aCopyProperties) + { + if ( m_xObjectPSI->hasPropertyByName( aCopyProperty ) ) + _rxObject->setPropertyValue( aCopyProperty, m_xObject->getPropertyValue( aCopyProperty ) ); + } +} + +void ObjectCopySource::copyFilterAndSortingTo( const Reference< XConnection >& _xConnection,const Reference< XPropertySet >& _rxObject ) const +{ + std::pair< OUString, OUString > aProperties[] = { + std::pair< OUString, OUString >(PROPERTY_FILTER,OUString(" AND ")) + ,std::pair< OUString, OUString >(PROPERTY_ORDER,OUString(" ORDER BY ")) + }; + + try + { + const OUString sSourceName = ::dbtools::composeTableNameForSelect(m_xConnection,m_xObject) + "."; + const OUString sTargetName = ::dbtools::composeTableNameForSelect(_xConnection,_rxObject); + const OUString sTargetNameTemp = sTargetName + "."; + + OUStringBuffer sStatement = "SELECT * FROM " + sTargetName + " WHERE 0=1"; + + for (const std::pair<OUString,OUString> & aProperty : aProperties) + { + if ( m_xObjectPSI->hasPropertyByName( aProperty.first ) ) + { + OUString sFilter; + m_xObject->getPropertyValue( aProperty.first ) >>= sFilter; + if ( !sFilter.isEmpty() ) + { + sStatement.append(aProperty.second); + sFilter = sFilter.replaceFirst(sSourceName,sTargetNameTemp); + _rxObject->setPropertyValue( aProperty.first, Any(sFilter) ); + sStatement.append(sFilter); + } + } + } + + _xConnection->createStatement()->executeQuery(sStatement.makeStringAndClear()); + + if ( m_xObjectPSI->hasPropertyByName( PROPERTY_APPLYFILTER ) ) + _rxObject->setPropertyValue( PROPERTY_APPLYFILTER, m_xObject->getPropertyValue( PROPERTY_APPLYFILTER ) ); + } + catch(Exception&) + { + } +} + +Sequence< OUString > ObjectCopySource::getColumnNames() const +{ + return m_xObjectColumns->getElementNames(); +} + +Sequence< OUString > ObjectCopySource::getPrimaryKeyColumnNames() const +{ + const Reference<XNameAccess> xPrimaryKeyColumns = getPrimaryKeyColumns_throw(m_xObject); + Sequence< OUString > aKeyColNames; + if ( xPrimaryKeyColumns.is() ) + aKeyColNames = xPrimaryKeyColumns->getElementNames(); + return aKeyColNames; +} + +OFieldDescription* ObjectCopySource::createFieldDescription( const OUString& _rColumnName ) const +{ + Reference< XPropertySet > xColumn( m_xObjectColumns->getByName( _rColumnName ), UNO_QUERY_THROW ); + return new OFieldDescription( xColumn ); +} + +OUString ObjectCopySource::getSelectStatement() const +{ + OUString sSelectStatement; + if ( m_xObjectPSI->hasPropertyByName( PROPERTY_COMMAND ) ) + { // query + OSL_VERIFY( m_xObject->getPropertyValue( PROPERTY_COMMAND ) >>= sSelectStatement ); + } + else + { // table + OUStringBuffer aSQL; + aSQL.append( "SELECT " ); + + // we need to create the sql stmt with column names + // otherwise it is possible that names don't match + const OUString sQuote = m_xMetaData->getIdentifierQuoteString(); + + Sequence< OUString > aColumnNames = getColumnNames(); + const OUString* pColumnName = aColumnNames.getConstArray(); + const OUString* pEnd = pColumnName + aColumnNames.getLength(); + for ( ; pColumnName != pEnd; ) + { + aSQL.append( ::dbtools::quoteName( sQuote, *pColumnName++ ) ); + + if ( pColumnName == pEnd ) + aSQL.append( " " ); + else + aSQL.append( ", " ); + } + + aSQL.append( "FROM " + ::dbtools::composeTableNameForSelect( m_xConnection, m_xObject ) ); + + sSelectStatement = aSQL.makeStringAndClear(); + } + + return sSelectStatement; +} + +::utl::SharedUNOComponent< XPreparedStatement > ObjectCopySource::getPreparedSelectStatement() const +{ + ::utl::SharedUNOComponent< XPreparedStatement > xStatement( + m_xConnection->prepareStatement( getSelectStatement() ), + ::utl::SharedUNOComponent< XPreparedStatement >::TakeOwnership + ); + return xStatement; +} + +// NamedTableCopySource +NamedTableCopySource::NamedTableCopySource( const Reference< XConnection >& _rxConnection, const OUString& _rTableName ) + :m_xConnection( _rxConnection, UNO_SET_THROW ) + ,m_xMetaData( _rxConnection->getMetaData(), UNO_SET_THROW ) + ,m_sTableName( _rTableName ) +{ + ::dbtools::qualifiedNameComponents( m_xMetaData, m_sTableName, m_sTableCatalog, m_sTableSchema, m_sTableBareName, ::dbtools::EComposeRule::Complete ); + impl_ensureColumnInfo_throw(); +} + +OUString NamedTableCopySource::getQualifiedObjectName() const +{ + return m_sTableName; +} + +bool NamedTableCopySource::isView() const +{ + OUString sTableType; + try + { + Reference< XResultSet > xTableDesc( m_xMetaData->getTables( Any( m_sTableCatalog ), m_sTableSchema, m_sTableBareName, + Sequence< OUString >() ) ); + Reference< XRow > xTableDescRow( xTableDesc, UNO_QUERY_THROW ); + OSL_VERIFY( xTableDesc->next() ); + sTableType = xTableDescRow->getString( 4 ); + OSL_ENSURE( !xTableDescRow->wasNull(), "NamedTableCopySource::isView: invalid table type!" ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + return sTableType == "VIEW"; +} + +void NamedTableCopySource::copyUISettingsTo( const Reference< XPropertySet >& /*_rxObject*/ ) const +{ + // not supported: we do not have UI settings to copy +} + +void NamedTableCopySource::copyFilterAndSortingTo( const Reference< XConnection >& ,const Reference< XPropertySet >& /*_rxObject*/ ) const +{ +} + +void NamedTableCopySource::impl_ensureColumnInfo_throw() +{ + if ( !m_aColumnInfo.empty() ) + return; + + Reference< XResultSetMetaDataSupplier > xStatementMetaSupp( impl_ensureStatement_throw().getTyped(), UNO_QUERY_THROW ); + Reference< XResultSetMetaData > xStatementMeta( xStatementMetaSupp->getMetaData(), UNO_SET_THROW ); + + sal_Int32 nColCount( xStatementMeta->getColumnCount() ); + for ( sal_Int32 i = 1; i <= nColCount; ++i ) + { + OFieldDescription aDesc; + + aDesc.SetName( xStatementMeta->getColumnName( i ) ); + aDesc.SetHelpText( xStatementMeta->getColumnLabel( i ) ); + aDesc.SetTypeValue( xStatementMeta->getColumnType( i ) ); + aDesc.SetTypeName( xStatementMeta->getColumnTypeName( i ) ); + aDesc.SetPrecision( xStatementMeta->getPrecision( i ) ); + aDesc.SetScale( xStatementMeta->getScale( i ) ); + aDesc.SetIsNullable( xStatementMeta->isNullable( i ) ); + aDesc.SetCurrency( xStatementMeta->isCurrency( i ) ); + aDesc.SetAutoIncrement( xStatementMeta->isAutoIncrement( i ) ); + + m_aColumnInfo.push_back( aDesc ); + } +} + +::utl::SharedUNOComponent< XPreparedStatement > const & NamedTableCopySource::impl_ensureStatement_throw() +{ + if ( !m_xStatement.is() ) + m_xStatement.set( m_xConnection->prepareStatement( getSelectStatement() ), UNO_SET_THROW ); + return m_xStatement; +} + +Sequence< OUString > NamedTableCopySource::getColumnNames() const +{ + Sequence< OUString > aNames( m_aColumnInfo.size() ); + std::transform(m_aColumnInfo.begin(), m_aColumnInfo.end(), aNames.getArray(), + [](const auto& elem) { return elem.GetName(); }); + + return aNames; +} + +Sequence< OUString > NamedTableCopySource::getPrimaryKeyColumnNames() const +{ + Sequence< OUString > aPKColNames; + + try + { + Reference< XResultSet > xPKDesc( m_xMetaData->getPrimaryKeys( Any( m_sTableCatalog ), m_sTableSchema, m_sTableBareName ) ); + Reference< XRow > xPKDescRow( xPKDesc, UNO_QUERY_THROW ); + while ( xPKDesc->next() ) + { + sal_Int32 len( aPKColNames.getLength() ); + aPKColNames.realloc( len + 1 ); + aPKColNames.getArray()[ len ] = xPKDescRow->getString( 4 ); // COLUMN_NAME + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + return aPKColNames; +} + +OFieldDescription* NamedTableCopySource::createFieldDescription( const OUString& _rColumnName ) const +{ + for (auto const& elem : m_aColumnInfo) + if ( elem.GetName() == _rColumnName ) + return new OFieldDescription(elem); + + return nullptr; +} + +OUString NamedTableCopySource::getSelectStatement() const +{ + return "SELECT * FROM " + + ::dbtools::composeTableNameForSelect( m_xConnection, m_sTableCatalog, m_sTableSchema, m_sTableBareName ); +} + +::utl::SharedUNOComponent< XPreparedStatement > NamedTableCopySource::getPreparedSelectStatement() const +{ + return const_cast< NamedTableCopySource* >( this )->impl_ensureStatement_throw(); +} + +namespace { + +// DummyCopySource +class DummyCopySource : public ICopyTableSourceObject +{ +public: + DummyCopySource() { } + + static const DummyCopySource& Instance(); + + // ICopyTableSourceObject overridables + virtual OUString getQualifiedObjectName() const override; + virtual bool isView() const override; + virtual void copyUISettingsTo( const css::uno::Reference< css::beans::XPropertySet >& _rxObject ) const override; + virtual void copyFilterAndSortingTo(const css::uno::Reference< css::sdbc::XConnection >& _xConnection, const css::uno::Reference< css::beans::XPropertySet >& _rxObject ) const override; + virtual css::uno::Sequence< OUString > + getColumnNames() const override; + virtual css::uno::Sequence< OUString > + getPrimaryKeyColumnNames() const override; + virtual OFieldDescription* createFieldDescription( const OUString& _rColumnName ) const override; + virtual OUString getSelectStatement() const override; + virtual ::utl::SharedUNOComponent< XPreparedStatement > + getPreparedSelectStatement() const override; +}; + +} + +const DummyCopySource& DummyCopySource::Instance() +{ + static DummyCopySource s_aTheInstance; + return s_aTheInstance; +} + +OUString DummyCopySource::getQualifiedObjectName() const +{ + SAL_WARN("dbaccess.ui", "DummyCopySource::getQualifiedObjectName: not to be called!" ); + return OUString(); +} + +bool DummyCopySource::isView() const +{ + SAL_WARN("dbaccess.ui", "DummyCopySource::isView: not to be called!" ); + return false; +} + +void DummyCopySource::copyUISettingsTo( const Reference< XPropertySet >& /*_rxObject*/ ) const +{ + // no support +} + +void DummyCopySource::copyFilterAndSortingTo( const Reference< XConnection >& ,const Reference< XPropertySet >& /*_rxObject*/ ) const +{ +} + +Sequence< OUString > DummyCopySource::getColumnNames() const +{ + return Sequence< OUString >(); +} + +Sequence< OUString > DummyCopySource::getPrimaryKeyColumnNames() const +{ + SAL_WARN("dbaccess.ui", "DummyCopySource::getPrimaryKeyColumnNames: not to be called!" ); + return Sequence< OUString >(); +} + +OFieldDescription* DummyCopySource::createFieldDescription( const OUString& /*_rColumnName*/ ) const +{ + SAL_WARN("dbaccess.ui", "DummyCopySource::createFieldDescription: not to be called!" ); + return nullptr; +} + +OUString DummyCopySource::getSelectStatement() const +{ + SAL_WARN("dbaccess.ui", "DummyCopySource::getSelectStatement: not to be called!" ); + return OUString(); +} + +::utl::SharedUNOComponent< XPreparedStatement > DummyCopySource::getPreparedSelectStatement() const +{ + SAL_WARN("dbaccess.ui", "DummyCopySource::getPreparedSelectStatement: not to be called!" ); + return ::utl::SharedUNOComponent< XPreparedStatement >(); +} + +namespace +{ + bool lcl_canCreateViewFor_nothrow( const Reference< XConnection >& _rxConnection ) + { + Reference< XViewsSupplier > xSup( _rxConnection, UNO_QUERY ); + Reference< XDataDescriptorFactory > xViewFac; + if ( xSup.is() ) + xViewFac.set( xSup->getViews(), UNO_QUERY ); + return xViewFac.is(); + } + + bool lcl_sameConnection_throw( const Reference< XConnection >& _rxLHS, const Reference< XConnection >& _rxRHS ) + { + Reference< XDatabaseMetaData > xMetaLHS( _rxLHS->getMetaData(), UNO_SET_THROW ); + Reference< XDatabaseMetaData > xMetaRHS( _rxRHS->getMetaData(), UNO_SET_THROW ); + return xMetaLHS->getURL() == xMetaRHS->getURL(); + } +} + +// OCopyTableWizard +OCopyTableWizard::OCopyTableWizard(weld::Window* pParent, const OUString& _rDefaultName, sal_Int16 _nOperation, + const ICopyTableSourceObject& _rSourceObject, const Reference< XConnection >& _xSourceConnection, + const Reference< XConnection >& _xConnection, const Reference< XComponentContext >& _rxContext, + const Reference< XInteractionHandler>& _xInteractionHandler) + : vcl::RoadmapWizardMachine(pParent) + , m_mNameMapping(_xConnection->getMetaData().is() && _xConnection->getMetaData()->supportsMixedCaseQuotedIdentifiers()) + , m_xDestConnection( _xConnection ) + , m_rSourceObject( _rSourceObject ) + , m_xFormatter( getNumberFormatter( _xConnection, _rxContext ) ) + , m_xContext(_rxContext) + , m_xInteractionHandler(_xInteractionHandler) + , m_sTypeNames(DBA_RES(STR_TABLEDESIGN_DBFIELDTYPES)) + , m_nPageCount(0) + , m_bDeleteSourceColumns(true) + , m_bInterConnectionCopy( _xSourceConnection != _xConnection ) + , m_sName( _rDefaultName ) + , m_nOperation( _nOperation ) + , m_ePressed( WIZARD_NONE ) + , m_bCreatePrimaryKeyColumn(false) + , m_bUseHeaderLine(false) +{ + construct(); + + // extract table name + OUString sInitialTableName( _rDefaultName ); + try + { + m_sSourceName = m_rSourceObject.getQualifiedObjectName(); + OSL_ENSURE( !m_sSourceName.isEmpty(), "OCopyTableWizard::OCopyTableWizard: unable to retrieve the source object's name!" ); + + if ( sInitialTableName.isEmpty() ) + sInitialTableName = m_sSourceName; + + if ( m_sName.isEmpty() ) + { + if ( _xSourceConnection == m_xDestConnection ) + { + Reference< XTablesSupplier > xSup( m_xDestConnection, UNO_QUERY_THROW ); + m_sName = ::dbtools::createUniqueName( xSup->getTables(), sInitialTableName, false ); + } + else + m_sName = sInitialTableName; + } + } + catch ( const Exception& ) + { + m_sName = sInitialTableName; + } + + ::dbaui::fillTypeInfo( _xSourceConnection, m_sTypeNames, m_aTypeInfo, m_aTypeInfoIndex ); + ::dbaui::fillTypeInfo( m_xDestConnection, m_sTypeNames, m_aDestTypeInfo, m_aDestTypeInfoIndex ); + loadData( m_rSourceObject, m_vSourceColumns, m_vSourceVec ); + + bool bAllowViews = true; + // if the source is a, don't allow creating views + if ( m_rSourceObject.isView() ) + bAllowViews = false; + // no views if the target connection does not support creating them + if ( !lcl_canCreateViewFor_nothrow( m_xDestConnection ) ) + bAllowViews = false; + // no views if we're copying to a different database + if ( !lcl_sameConnection_throw( _xSourceConnection, m_xDestConnection ) ) + bAllowViews = false; + + if ( m_bInterConnectionCopy ) + { + Reference< XDatabaseMetaData > xSrcMeta = _xSourceConnection->getMetaData(); + OUString sCatalog; + OUString sSchema; + OUString sTable; + ::dbtools::qualifiedNameComponents( xSrcMeta, + m_sName, + sCatalog, + sSchema, + sTable, + ::dbtools::EComposeRule::InDataManipulation); + + m_sName = ::dbtools::composeTableName(m_xDestConnection->getMetaData(),sCatalog,sSchema,sTable,false,::dbtools::EComposeRule::InTableDefinitions); + } + + std::unique_ptr<OCopyTable> xPage1(new OCopyTable(CreatePageContainer(), this)); + xPage1->disallowUseHeaderLine(); + if ( !bAllowViews ) + xPage1->disallowViews(); + xPage1->setCreateStyleAction(); + AddWizardPage(std::move(xPage1)); + + AddWizardPage( std::make_unique<OWizNameMatching>(CreatePageContainer(), this)); + AddWizardPage( std::make_unique<OWizColumnSelect>(CreatePageContainer(), this)); + AddWizardPage( std::make_unique<OWizNormalExtend>(CreatePageContainer(), this)); + ActivatePage(); + + m_xAssistant->set_current_page(0); +} + +weld::Container* OCopyTableWizard::CreatePageContainer() +{ + OString sIdent(OString::number(m_nPageCount)); + weld::Container* pPageContainer = m_xAssistant->append_page(sIdent); + return pPageContainer; +} + +OCopyTableWizard::OCopyTableWizard( weld::Window* pParent, const OUString& _rDefaultName, sal_Int16 _nOperation, + ODatabaseExport::TColumns&& _rSourceColumns, const ODatabaseExport::TColumnVector& _rSourceColVec, + const Reference< XConnection >& _xConnection, const Reference< XNumberFormatter >& _xFormatter, + TypeSelectionPageFactory _pTypeSelectionPageFactory, SvStream& _rTypeSelectionPageArg, const Reference< XComponentContext >& _rxContext ) + : vcl::RoadmapWizardMachine(pParent) + , m_vSourceColumns(std::move(_rSourceColumns)) + , m_mNameMapping(_xConnection->getMetaData().is() && _xConnection->getMetaData()->supportsMixedCaseQuotedIdentifiers()) + , m_xDestConnection( _xConnection ) + , m_rSourceObject( DummyCopySource::Instance() ) + , m_xFormatter(_xFormatter) + , m_xContext(_rxContext) + , m_sTypeNames(DBA_RES(STR_TABLEDESIGN_DBFIELDTYPES)) + , m_nPageCount(0) + , m_bDeleteSourceColumns(false) + , m_bInterConnectionCopy( false ) + , m_sName(_rDefaultName) + , m_nOperation( _nOperation ) + , m_ePressed( WIZARD_NONE ) + , m_bCreatePrimaryKeyColumn(false) + , m_bUseHeaderLine(false) +{ + construct(); + for (auto const& sourceCol : _rSourceColVec) + { + m_vSourceVec.emplace_back(m_vSourceColumns.find(sourceCol->first)); + } + + ::dbaui::fillTypeInfo( _xConnection, m_sTypeNames, m_aTypeInfo, m_aTypeInfoIndex ); + ::dbaui::fillTypeInfo( _xConnection, m_sTypeNames, m_aDestTypeInfo, m_aDestTypeInfoIndex ); + + m_xInteractionHandler = InteractionHandler::createWithParent(m_xContext, nullptr); + + std::unique_ptr<OCopyTable> xPage1(new OCopyTable(CreatePageContainer(), this)); + xPage1->disallowViews(); + xPage1->setCreateStyleAction(); + AddWizardPage(std::move(xPage1)); + + AddWizardPage(std::make_unique<OWizNameMatching>(CreatePageContainer(), this)); + AddWizardPage(std::make_unique<OWizColumnSelect>(CreatePageContainer(), this)); + AddWizardPage((*_pTypeSelectionPageFactory)(CreatePageContainer(), this, _rTypeSelectionPageArg)); + + ActivatePage(); + + m_xAssistant->set_current_page(0); +} + +void OCopyTableWizard::construct() +{ + m_xAssistant->set_size_request(700, 350); + + m_xPrevPage->set_label(DBA_RES(STR_WIZ_PB_PREV)); + m_xNextPage->set_label(DBA_RES(STR_WIZ_PB_NEXT)); + m_xFinish->set_label(DBA_RES(STR_WIZ_PB_OK)); + + m_xHelp->show(); + m_xCancel->show(); + m_xPrevPage->show(); + m_xNextPage->show(); + m_xFinish->show(); + + m_xPrevPage->connect_clicked( LINK( this, OCopyTableWizard, ImplPrevHdl ) ); + m_xNextPage->connect_clicked( LINK( this, OCopyTableWizard, ImplNextHdl ) ); + m_xFinish->connect_clicked( LINK( this, OCopyTableWizard, ImplOKHdl ) ); + + m_xNextPage->grab_focus(); + + if (!m_vDestColumns.empty()) + // source is a html or rtf table + m_xAssistant->change_default_widget(nullptr, m_xNextPage.get()); + else + m_xAssistant->change_default_widget(nullptr, m_xFinish.get()); + + m_pTypeInfo = std::make_shared<OTypeInfo>(); + m_pTypeInfo->aUIName = m_sTypeNames.getToken(TYPE_OTHER, ';'); + m_bAddPKFirstTime = true; +} + +OCopyTableWizard::~OCopyTableWizard() +{ + if ( m_bDeleteSourceColumns ) + clearColumns(m_vSourceColumns,m_vSourceVec); + + clearColumns(m_vDestColumns,m_aDestVec); + + // clear the type information + m_aTypeInfoIndex.clear(); + m_aTypeInfo.clear(); + m_aDestTypeInfoIndex.clear(); + m_aDestTypeInfo.clear(); +} + +IMPL_LINK_NOARG(OCopyTableWizard, ImplPrevHdl, weld::Button&, void) +{ + m_ePressed = WIZARD_PREV; + if ( GetCurLevel() ) + { + if ( getOperation() != CopyTableOperation::AppendData ) + { + if(GetCurLevel() == 2) + ShowPage(GetCurLevel()-2); + else + ShowPrevPage(); + } + else + ShowPrevPage(); + } +} + +IMPL_LINK_NOARG(OCopyTableWizard, ImplNextHdl, weld::Button&, void) +{ + m_ePressed = WIZARD_NEXT; + if ( GetCurLevel() < MAX_PAGES ) + { + if ( getOperation() != CopyTableOperation::AppendData ) + { + if(GetCurLevel() == 0) + ShowPage(GetCurLevel()+2); + else + ShowNextPage(); + } + else + ShowNextPage(); + } +} + +bool OCopyTableWizard::CheckColumns(sal_Int32& _rnBreakPos) +{ + bool bRet = true; + m_vColumnPositions.clear(); + m_vColumnTypes.clear(); + + OSL_ENSURE( m_xDestConnection.is(), "OCopyTableWizard::CheckColumns: No connection!" ); + // If database is able to process PrimaryKeys, set PrimaryKey + if ( m_xDestConnection.is() ) + { + bool bPKeyAllowed = supportsPrimaryKey(); + + bool bContainsColumns = !m_vDestColumns.empty(); + + if ( bPKeyAllowed && shouldCreatePrimaryKey() ) + { + // add extra column for the primary key + TOTypeInfoSP pTypeInfo = queryPrimaryKeyType(m_aDestTypeInfo); + if ( pTypeInfo ) + { + if ( m_bAddPKFirstTime ) + { + // tdf#114955: since we chose to create a primary key + // be sure all other columns won't be in primary key + for (auto const& elem : m_vDestColumns) + elem.second->SetPrimaryKey(false); + OFieldDescription* pField = new OFieldDescription(); + pField->SetName(m_aKeyName); + pField->FillFromTypeInfo(pTypeInfo,true,true); + pField->SetPrimaryKey(true); + m_bAddPKFirstTime = false; + insertColumn(0,pField); + } + m_vColumnPositions.emplace_back(1,1); + m_vColumnTypes.push_back(pTypeInfo->nType); + } + } + + if ( bContainsColumns ) + { // we have dest columns so look for the matching column + for (auto const& elemSource : m_vSourceVec) + { + ODatabaseExport::TColumns::const_iterator aDestIter = m_vDestColumns.find(m_mNameMapping[elemSource->first]); + + if ( aDestIter != m_vDestColumns.end() ) + { + ODatabaseExport::TColumnVector::const_iterator aFind = std::find(m_aDestVec.begin(),m_aDestVec.end(),aDestIter); + assert(aFind != m_aDestVec.end()); + sal_Int32 nPos = (aFind - m_aDestVec.begin())+1; + m_vColumnPositions.emplace_back(nPos,nPos); + m_vColumnTypes.push_back((*aFind)->second->GetType()); + } + else + { + m_vColumnPositions.emplace_back( COLUMN_POSITION_NOT_FOUND, COLUMN_POSITION_NOT_FOUND ); + m_vColumnTypes.push_back(0); + } + } + } + else + { + Reference< XDatabaseMetaData > xMetaData( m_xDestConnection->getMetaData() ); + OUString sExtraChars = xMetaData->getExtraNameCharacters(); + sal_Int32 nMaxNameLen = getMaxColumnNameLength(); + + _rnBreakPos=0; + for (auto const& elemSource : m_vSourceVec) + { + OFieldDescription* pField = new OFieldDescription(*elemSource->second); + pField->SetName(convertColumnName(TExportColumnFindFunctor(&m_vDestColumns),elemSource->first,sExtraChars,nMaxNameLen)); + TOTypeInfoSP pType = convertType(elemSource->second->getSpecialTypeInfo(),bRet); + pField->SetType(pType); + if ( !bPKeyAllowed ) + pField->SetPrimaryKey(false); + + // now create a column + insertColumn(m_vDestColumns.size(),pField); + m_vColumnPositions.emplace_back(m_vDestColumns.size(),m_vDestColumns.size()); + m_vColumnTypes.push_back(elemSource->second->GetType()); + ++_rnBreakPos; + if (!bRet) + break; + } + } + } + return bRet; +} + +IMPL_LINK_NOARG(OCopyTableWizard, ImplOKHdl, weld::Button&, void) +{ + m_ePressed = WIZARD_FINISH; + bool bFinish = DeactivatePage(); + + if(!bFinish) + return; + + weld::WaitObject aWait(m_xAssistant.get()); + switch(getOperation()) + { + case CopyTableOperation::CopyDefinitionAndData: + case CopyTableOperation::CopyDefinitionOnly: + { + bool bOnFirstPage = GetCurLevel() == 0; + if ( bOnFirstPage ) + { + // we came from the first page so we have to clear + // all column information already collected + clearDestColumns(); + m_mNameMapping.clear(); + } + sal_Int32 nBreakPos = 0; + bool bCheckOk = CheckColumns(nBreakPos); + if ( bOnFirstPage && !bCheckOk ) + { + showColumnTypeNotSupported(m_vSourceVec[nBreakPos-1]->first); + OWizTypeSelect* pPage = static_cast<OWizTypeSelect*>(GetPage(3)); + if ( pPage ) + { + m_mNameMapping.clear(); + pPage->setDisplayRow(nBreakPos); + ShowPage(3); + return; + } + } + if ( m_xDestConnection.is() ) + { + if ( supportsPrimaryKey() ) + { + bool noPrimaryKey = std::none_of(m_vDestColumns.begin(),m_vDestColumns.end(), + [] (const ODatabaseExport::TColumns::value_type& tCol) { return tCol.second->IsPrimaryKey(); }); + if ( noPrimaryKey && m_xInteractionHandler.is() ) + { + + OUString sMsg(DBA_RES(STR_TABLEDESIGN_NO_PRIM_KEY)); + SQLContext aError; + aError.Message = sMsg; + ::rtl::Reference xRequest( new ::comphelper::OInteractionRequest( Any( aError ) ) ); + ::rtl::Reference xYes = new ::comphelper::OInteractionApprove; + xRequest->addContinuation( xYes ); + xRequest->addContinuation( new ::comphelper::OInteractionDisapprove ); + ::rtl::Reference< ::comphelper::OInteractionAbort > xAbort = new ::comphelper::OInteractionAbort; + xRequest->addContinuation( xAbort ); + + m_xInteractionHandler->handle( xRequest ); + + if ( xYes->wasSelected() ) + { + OCopyTable* pPage = static_cast<OCopyTable*>(GetPage(0)); + m_bCreatePrimaryKeyColumn = true; + m_aKeyName = pPage->GetKeyName(); + if ( m_aKeyName.isEmpty() ) + m_aKeyName = "ID"; + m_aKeyName = createUniqueName( m_aKeyName ); + sal_Int32 nBreakPos2 = 0; + CheckColumns(nBreakPos2); + } + else if ( xAbort->wasSelected() ) + { + ShowPage(3); + return; + } + } + } + } + break; + } + case CopyTableOperation::AppendData: + case CopyTableOperation::CreateAsView: + break; + default: + { + SAL_WARN("dbaccess.ui", "OCopyTableWizard::ImplOKHdl: invalid creation style!"); + } + } + + m_xAssistant->response(RET_OK); +} + +void OCopyTableWizard::setCreatePrimaryKey( bool _bDoCreate, const OUString& _rSuggestedName ) +{ + m_bCreatePrimaryKeyColumn = _bDoCreate; + if ( !_rSuggestedName.isEmpty() ) + m_aKeyName = _rSuggestedName; + + OCopyTable* pSettingsPage = dynamic_cast< OCopyTable* >( GetPage( 0 ) ); + OSL_ENSURE( pSettingsPage, "OCopyTableWizard::setCreatePrimaryKey: page should have been added in the ctor!" ); + if ( pSettingsPage ) + pSettingsPage->setCreatePrimaryKey( _bDoCreate, _rSuggestedName ); +} + +void OCopyTableWizard::ActivatePage() +{ + OWizardPage* pCurrent = static_cast<OWizardPage*>(GetPage(GetCurLevel())); + if (pCurrent) + { + bool bFirstTime = pCurrent->IsFirstTime(); + if(bFirstTime) + pCurrent->Reset(); + + CheckButtons(); + + m_xAssistant->set_title(pCurrent->GetTitle()); + } +} + +void OCopyTableWizard::CheckButtons() +{ + if(GetCurLevel() == 0) // the first page has no back button + { + if(m_nPageCount > 1) + m_xNextPage->set_sensitive(true); + else + m_xNextPage->set_sensitive(false); + + m_xPrevPage->set_sensitive(false); + } + else if(GetCurLevel() == m_nPageCount-1) // the last page has no next button + { + m_xNextPage->set_sensitive(false); + m_xPrevPage->set_sensitive(true); + } + else + { + m_xPrevPage->set_sensitive(true); + // next already has its state + } +} + +void OCopyTableWizard::EnableNextButton(bool bEnable) +{ + m_xNextPage->set_sensitive(bEnable); +} + +bool OCopyTableWizard::DeactivatePage() +{ + OWizardPage* pPage = static_cast<OWizardPage*>(GetPage(GetCurLevel())); + return pPage && pPage->LeavePage(); +} + +void OCopyTableWizard::AddWizardPage(std::unique_ptr<OWizardPage> xPage) +{ + AddPage(std::move(xPage)); + ++m_nPageCount; +} + +void OCopyTableWizard::insertColumn(sal_Int32 _nPos,OFieldDescription* _pField) +{ + OSL_ENSURE(_pField,"FieldDescrioption is null!"); + if ( !_pField ) + return; + + ODatabaseExport::TColumns::const_iterator aFind = m_vDestColumns.find(_pField->GetName()); + if ( aFind != m_vDestColumns.end() ) + { + delete aFind->second; + m_vDestColumns.erase(aFind); + } + + m_aDestVec.insert(m_aDestVec.begin() + _nPos, + m_vDestColumns.emplace(_pField->GetName(),_pField).first); + m_mNameMapping[_pField->GetName()] = _pField->GetName(); +} + +void OCopyTableWizard::replaceColumn(sal_Int32 _nPos,OFieldDescription* _pField,const OUString& _sOldName) +{ + OSL_ENSURE(_pField,"FieldDescrioption is null!"); + if ( _pField ) + { + m_vDestColumns.erase(_sOldName); + OSL_ENSURE( m_vDestColumns.find(_pField->GetName()) == m_vDestColumns.end(),"Column with that name already exist!"); + + m_aDestVec[_nPos] = m_vDestColumns.emplace(_pField->GetName(),_pField).first; + } +} + +void OCopyTableWizard::loadData( const ICopyTableSourceObject& _rSourceObject, ODatabaseExport::TColumns& _rColumns, ODatabaseExport::TColumnVector& _rColVector ) +{ + for (auto const& column : _rColumns) + delete column.second; + + _rColVector.clear(); + _rColumns.clear(); + + OFieldDescription* pActFieldDescr = nullptr; + OUString const sCreateParam("x"); + // ReadOnly-Flag + // On drop no line must be editable. + // On add only empty lines must be editable. + // On Add and Drop all lines can be edited. + Sequence< OUString > aColumns( _rSourceObject.getColumnNames() ); + const OUString* pColumn = aColumns.getConstArray(); + const OUString* pColumnEnd = pColumn + aColumns.getLength(); + + for ( ; pColumn != pColumnEnd; ++pColumn ) + { + // get the properties of the column + pActFieldDescr = _rSourceObject.createFieldDescription( *pColumn ); + OSL_ENSURE( pActFieldDescr, "OCopyTableWizard::loadData: illegal field description!" ); + if ( !pActFieldDescr ) + continue; + + sal_Int32 nType = pActFieldDescr->GetType(); + sal_Int32 nScale = pActFieldDescr->GetScale(); + sal_Int32 nPrecision = pActFieldDescr->GetPrecision(); + bool bAutoIncrement = pActFieldDescr->IsAutoIncrement(); + OUString sTypeName = pActFieldDescr->GetTypeName(); + + // search for type + bool bForce; + TOTypeInfoSP pTypeInfo = ::dbaui::getTypeInfoFromType(m_aTypeInfo,nType,sTypeName,sCreateParam,nPrecision,nScale,bAutoIncrement,bForce); + if ( !pTypeInfo ) + pTypeInfo = m_pTypeInfo; + + pActFieldDescr->FillFromTypeInfo(pTypeInfo,true,false); + _rColVector.emplace_back(_rColumns.emplace(pActFieldDescr->GetName(),pActFieldDescr).first); + } + + // determine which columns belong to the primary key + Sequence< OUString > aPrimaryKeyColumns( _rSourceObject.getPrimaryKeyColumnNames() ); + const OUString* pKeyColName = aPrimaryKeyColumns.getConstArray(); + const OUString* pKeyColEnd = pKeyColName + aPrimaryKeyColumns.getLength(); + + for( ; pKeyColName != pKeyColEnd; ++pKeyColName ) + { + ODatabaseExport::TColumns::const_iterator keyPos = _rColumns.find( *pKeyColName ); + if ( keyPos != _rColumns.end() ) + { + keyPos->second->SetPrimaryKey( true ); + keyPos->second->SetIsNullable( ColumnValue::NO_NULLS ); + } + } +} + +void OCopyTableWizard::clearDestColumns() +{ + clearColumns(m_vDestColumns,m_aDestVec); + m_bAddPKFirstTime = true; + m_mNameMapping.clear(); +} + +void OCopyTableWizard::appendColumns( Reference<XColumnsSupplier> const & _rxColSup, const ODatabaseExport::TColumnVector* _pVec, bool _bKeyColumns) +{ + // now append the columns + OSL_ENSURE(_rxColSup.is(),"No columns supplier"); + if(!_rxColSup.is()) + return; + Reference<XNameAccess> xColumns = _rxColSup->getColumns(); + OSL_ENSURE(xColumns.is(),"No columns"); + Reference<XDataDescriptorFactory> xColumnFactory(xColumns,UNO_QUERY); + + Reference<XAppend> xAppend(xColumns,UNO_QUERY); + OSL_ENSURE(xAppend.is(),"No XAppend Interface!"); + + for (auto const& elem : *_pVec) + { + OFieldDescription* pField = elem->second; + if(!pField) + continue; + + Reference<XPropertySet> xColumn; + if(pField->IsPrimaryKey() || !_bKeyColumns) + xColumn = xColumnFactory->createDataDescriptor(); + if(xColumn.is()) + { + if(!_bKeyColumns) + dbaui::setColumnProperties(xColumn,pField); + else + xColumn->setPropertyValue(PROPERTY_NAME,Any(pField->GetName())); + + xAppend->appendByDescriptor(xColumn); + xColumn = nullptr; + // now only the settings are missing + if(xColumns->hasByName(pField->GetName())) + { + xColumn.set(xColumns->getByName(pField->GetName()),UNO_QUERY); + OSL_ENSURE(xColumn.is(),"OCopyTableWizard::appendColumns: Column is NULL!"); + if ( xColumn.is() ) + pField->copyColumnSettingsTo(xColumn); + } + else + { + SAL_WARN("dbaccess.ui", "OCopyTableWizard::appendColumns: invalid field name!"); + } + + } + } +} + +void OCopyTableWizard::appendKey( Reference<XKeysSupplier> const & _rxSup, const ODatabaseExport::TColumnVector* _pVec) +{ + if(!_rxSup.is()) + return; // the database doesn't support keys + OSL_ENSURE(_rxSup.is(),"No XKeysSupplier!"); + Reference<XDataDescriptorFactory> xKeyFactory(_rxSup->getKeys(),UNO_QUERY); + OSL_ENSURE(xKeyFactory.is(),"No XDataDescriptorFactory Interface!"); + if ( !xKeyFactory.is() ) + return; + Reference<XAppend> xAppend(xKeyFactory,UNO_QUERY); + OSL_ENSURE(xAppend.is(),"No XAppend Interface!"); + + Reference<XPropertySet> xKey = xKeyFactory->createDataDescriptor(); + OSL_ENSURE(xKey.is(),"Key is null!"); + xKey->setPropertyValue(PROPERTY_TYPE,Any(KeyType::PRIMARY)); + + Reference<XColumnsSupplier> xColSup(xKey,UNO_QUERY); + if(xColSup.is()) + { + appendColumns(xColSup,_pVec,true); + Reference<XNameAccess> xColumns = xColSup->getColumns(); + if(xColumns.is() && xColumns->getElementNames().hasElements()) + xAppend->appendByDescriptor(xKey); + } + +} + +Reference< XPropertySet > OCopyTableWizard::createView() const +{ + OUString sCommand( m_rSourceObject.getSelectStatement() ); + OSL_ENSURE( !sCommand.isEmpty(), "OCopyTableWizard::createView: no statement in the source object!" ); + // there are legitimate cases in which getSelectStatement does not provide a statement, + // but in all those cases, this method here should never be called. + return ::dbaui::createView( m_sName, m_xDestConnection, sCommand ); +} + +Reference< XPropertySet > OCopyTableWizard::returnTable() +{ + if ( getOperation() == CopyTableOperation::AppendData ) + return getTable(); + else + return createTable(); +} + +Reference< XPropertySet > OCopyTableWizard::getTable() const +{ + Reference< XPropertySet > xTable; + + Reference<XTablesSupplier> xSup( m_xDestConnection, UNO_QUERY ); + Reference< XNameAccess > xTables; + if(xSup.is()) + xTables = xSup->getTables(); + if(xTables.is() && xTables->hasByName(m_sName)) + xTables->getByName(m_sName) >>= xTable; + + return xTable; +} + +Reference< XPropertySet > OCopyTableWizard::createTable() +{ + Reference< XPropertySet > xTable; + + Reference<XTablesSupplier> xSup( m_xDestConnection, UNO_QUERY ); + Reference< XNameAccess > xTables; + if(xSup.is()) + xTables = xSup->getTables(); + Reference<XDataDescriptorFactory> xFact(xTables,UNO_QUERY); + OSL_ENSURE(xFact.is(),"No XDataDescriptorFactory available!"); + if(!xFact.is()) + return nullptr; + + xTable = xFact->createDataDescriptor(); + OSL_ENSURE(xTable.is(),"Could not create a new object!"); + if(!xTable.is()) + return nullptr; + + OUString sCatalog,sSchema,sTable; + Reference< XDatabaseMetaData> xMetaData = m_xDestConnection->getMetaData(); + ::dbtools::qualifiedNameComponents(xMetaData, + m_sName, + sCatalog, + sSchema, + sTable, + ::dbtools::EComposeRule::InDataManipulation); + + if ( sCatalog.isEmpty() && xMetaData->supportsCatalogsInTableDefinitions() ) + { + sCatalog = m_xDestConnection->getCatalog(); + } + + if ( sSchema.isEmpty() && xMetaData->supportsSchemasInTableDefinitions() ) + { + // query of current schema is quite inconsistent. In case of some + // DBMS's each user has their own schema. + sSchema = xMetaData->getUserName(); + // In case of mysql it is not that simple + if(xMetaData->getDatabaseProductName() == "MySQL") + { + Reference< XStatement > xSelect = m_xDestConnection->createStatement(); + Reference< XResultSet > xRs = xSelect->executeQuery("select database()"); + (void)xRs->next(); // first and only result + Reference< XRow > xRow( xRs, UNO_QUERY_THROW ); + sSchema = xRow->getString(1); + } + } + + xTable->setPropertyValue(PROPERTY_CATALOGNAME,Any(sCatalog)); + xTable->setPropertyValue(PROPERTY_SCHEMANAME,Any(sSchema)); + xTable->setPropertyValue(PROPERTY_NAME,Any(sTable)); + + Reference< XColumnsSupplier > xSuppDestinationColumns( xTable, UNO_QUERY ); + // now append the columns + const ODatabaseExport::TColumnVector& rVec = getDestVector(); + appendColumns( xSuppDestinationColumns, &rVec ); + // now append the primary key + Reference<XKeysSupplier> xKeySup(xTable,UNO_QUERY); + appendKey(xKeySup, &rVec); + + Reference<XAppend> xAppend(xTables,UNO_QUERY); + if(xAppend.is()) + xAppend->appendByDescriptor(xTable); + + // xTable = NULL; + // we need to reget the table because after appending it, it is no longer valid + if(xTables->hasByName(m_sName)) + xTables->getByName(m_sName) >>= xTable; + else + { + OUString sComposedName( + ::dbtools::composeTableName( m_xDestConnection->getMetaData(), xTable, ::dbtools::EComposeRule::InDataManipulation, false ) ); + if(xTables->hasByName(sComposedName)) + { + xTables->getByName(sComposedName) >>= xTable; + m_sName = sComposedName; + } + else + xTable = nullptr; + } + + if(xTable.is()) + { + xSuppDestinationColumns.set( xTable, UNO_QUERY_THROW ); + // insert new table name into table filter + ::dbaui::appendToFilter(m_xDestConnection, m_sName, GetComponentContext(), m_xAssistant.get()); + + // copy ui settings + m_rSourceObject.copyUISettingsTo( xTable ); + //copy filter and sorting + m_rSourceObject.copyFilterAndSortingTo(m_xDestConnection,xTable); + // set column mappings + Reference<XNameAccess> xNameAccess = xSuppDestinationColumns->getColumns(); + Sequence< OUString> aSeq = xNameAccess->getElementNames(); + const OUString* pIter = aSeq.getConstArray(); + const OUString* pEnd = pIter + aSeq.getLength(); + + for(sal_Int32 nNewPos=1;pIter != pEnd;++pIter,++nNewPos) + { + ODatabaseExport::TColumns::const_iterator aDestIter = m_vDestColumns.find(*pIter); + + if ( aDestIter != m_vDestColumns.end() ) + { + ODatabaseExport::TColumnVector::const_iterator aFind = std::find(m_aDestVec.begin(),m_aDestVec.end(),aDestIter); + sal_Int32 nPos = (aFind - m_aDestVec.begin())+1; + + ODatabaseExport::TPositions::iterator aPosFind = std::find_if( + m_vColumnPositions.begin(), + m_vColumnPositions.end(), + [nPos] (const ODatabaseExport::TPositions::value_type& tPos) { + return tPos.first == nPos; + } + ); + + if ( m_vColumnPositions.end() != aPosFind ) + { + aPosFind->second = nNewPos; + OSL_ENSURE( m_vColumnTypes.size() > o3tl::make_unsigned( aPosFind - m_vColumnPositions.begin() ), + "Invalid index for vector!" ); + m_vColumnTypes[ aPosFind - m_vColumnPositions.begin() ] = (*aFind)->second->GetType(); + } + } + } + } + + return xTable; +} + +bool OCopyTableWizard::supportsPrimaryKey( const Reference< XConnection >& _rxConnection ) +{ + OSL_PRECOND( _rxConnection.is(), "OCopyTableWizard::supportsPrimaryKey: invalid connection!" ); + if ( !_rxConnection.is() ) + return false; + + ::dbtools::DatabaseMetaData aMetaData( _rxConnection ); + return aMetaData.supportsPrimaryKeys(); +} + +bool OCopyTableWizard::supportsViews( const Reference< XConnection >& _rxConnection ) +{ + OSL_PRECOND( _rxConnection.is(), "OCopyTableWizard::supportsViews: invalid connection!" ); + if ( !_rxConnection.is() ) + return false; + + bool bSupportsViews( false ); + try + { + Reference< XDatabaseMetaData > xMetaData( _rxConnection->getMetaData(), UNO_SET_THROW ); + Reference< XViewsSupplier > xViewSups( _rxConnection, UNO_QUERY ); + bSupportsViews = xViewSups.is(); + if ( !bSupportsViews ) + { + try + { + Reference< XResultSet > xRs( xMetaData->getTableTypes(), UNO_SET_THROW ); + Reference< XRow > xRow( xRs, UNO_QUERY_THROW ); + while ( xRs->next() ) + { + OUString sValue = xRow->getString( 1 ); + if ( !xRow->wasNull() && sValue.equalsIgnoreAsciiCase("View") ) + { + bSupportsViews = true; + break; + } + } + } + catch( const SQLException& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + return bSupportsViews; +} + +sal_Int32 OCopyTableWizard::getMaxColumnNameLength() const +{ + sal_Int32 nLen = 0; + if ( m_xDestConnection.is() ) + { + try + { + Reference< XDatabaseMetaData > xMetaData( m_xDestConnection->getMetaData(), UNO_SET_THROW ); + nLen = xMetaData->getMaxColumnNameLength(); + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + return nLen; +} + +void OCopyTableWizard::setOperation( const sal_Int16 _nOperation ) +{ + m_nOperation = _nOperation; +} + + +OUString OCopyTableWizard::convertColumnName(const TColumnFindFunctor& _rCmpFunctor, + const OUString& _sColumnName, + std::u16string_view _sExtraChars, + sal_Int32 _nMaxNameLen) +{ + OUString sAlias = _sColumnName; + if ( isSQL92CheckEnabled( m_xDestConnection ) ) + sAlias = ::dbtools::convertName2SQLName(_sColumnName,_sExtraChars); + if((_nMaxNameLen && sAlias.getLength() > _nMaxNameLen) || _rCmpFunctor(sAlias)) + { + sal_Int32 nDiff = 1; + do + { + ++nDiff; + if(_nMaxNameLen && sAlias.getLength() >= _nMaxNameLen) + sAlias = sAlias.copy(0,sAlias.getLength() - (sAlias.getLength()-_nMaxNameLen+nDiff)); + + OUString sName(sAlias); + sal_Int32 nPos = 1; + sName += OUString::number(nPos); + + while(_rCmpFunctor(sName)) + { + sName = sAlias + OUString::number(++nPos); + } + sAlias = sName; + // we have to check again, it could happen that the name is already too long + } + while(_nMaxNameLen && sAlias.getLength() > _nMaxNameLen); + } + OSL_ENSURE(m_mNameMapping.find(_sColumnName) == m_mNameMapping.end(),"name doubled!"); + m_mNameMapping[_sColumnName] = sAlias; + return sAlias; +} + +void OCopyTableWizard::removeColumnNameFromNameMap(const OUString& _sName) +{ + m_mNameMapping.erase(_sName); +} + +bool OCopyTableWizard::supportsType(sal_Int32 _nDataType, sal_Int32& _rNewDataType) +{ + bool bRet = m_aDestTypeInfo.find(_nDataType) != m_aDestTypeInfo.end(); + if ( bRet ) + _rNewDataType = _nDataType; + return bRet; +} + +TOTypeInfoSP OCopyTableWizard::convertType(const TOTypeInfoSP& _pType, bool& _bNotConvert) +{ + if ( !m_bInterConnectionCopy ) + // no need to convert if the source and destination connection are the same + return _pType; + + bool bForce; + TOTypeInfoSP pType = ::dbaui::getTypeInfoFromType(m_aDestTypeInfo,_pType->nType,_pType->aTypeName,_pType->aCreateParams,_pType->nPrecision,_pType->nMaximumScale,_pType->bAutoIncrement,bForce); + if ( !pType || bForce ) + { // no type found so we have to find the correct one ourself + sal_Int32 nDefaultType = DataType::VARCHAR; + switch(_pType->nType) + { + case DataType::TINYINT: + if(supportsType(DataType::SMALLINT,nDefaultType)) + break; + [[fallthrough]]; + case DataType::SMALLINT: + if(supportsType(DataType::INTEGER,nDefaultType)) + break; + [[fallthrough]]; + case DataType::INTEGER: + if(supportsType(DataType::FLOAT,nDefaultType)) + break; + [[fallthrough]]; + case DataType::FLOAT: + if(supportsType(DataType::REAL,nDefaultType)) + break; + [[fallthrough]]; + case DataType::DATE: + case DataType::TIME: + if( DataType::DATE == _pType->nType || DataType::TIME == _pType->nType ) + { + if(supportsType(DataType::TIMESTAMP,nDefaultType)) + break; + } + [[fallthrough]]; + case DataType::TIMESTAMP: + case DataType::REAL: + case DataType::BIGINT: + if ( supportsType(DataType::DOUBLE,nDefaultType) ) + break; + [[fallthrough]]; + case DataType::DOUBLE: + if ( supportsType(DataType::NUMERIC,nDefaultType) ) + break; + [[fallthrough]]; + case DataType::NUMERIC: + supportsType(DataType::DECIMAL,nDefaultType); + break; + case DataType::DECIMAL: + if ( supportsType(DataType::NUMERIC,nDefaultType) ) + break; + if ( supportsType(DataType::DOUBLE,nDefaultType) ) + break; + break; + case DataType::VARCHAR: + if ( supportsType(DataType::LONGVARCHAR,nDefaultType) ) + break; + break; + case DataType::LONGVARCHAR: + if ( supportsType(DataType::CLOB,nDefaultType) ) + break; + break; + case DataType::BINARY: + if ( supportsType(DataType::VARBINARY,nDefaultType) ) + break; + break; + case DataType::VARBINARY: + if ( supportsType(DataType::LONGVARBINARY,nDefaultType) ) + break; + break; + case DataType::LONGVARBINARY: + if ( supportsType(DataType::BLOB,nDefaultType) ) + break; + if ( supportsType(DataType::LONGVARCHAR,nDefaultType) ) + break; + if ( supportsType(DataType::CLOB,nDefaultType) ) + break; + break; + default: + nDefaultType = DataType::VARCHAR; + } + pType = ::dbaui::getTypeInfoFromType(m_aDestTypeInfo,nDefaultType,_pType->aTypeName,_pType->aCreateParams,_pType->nPrecision,_pType->nMaximumScale,_pType->bAutoIncrement,bForce); + if ( !pType ) + { + _bNotConvert = false; + pType = ::dbaui::getTypeInfoFromType(m_aDestTypeInfo,DataType::VARCHAR,_pType->aTypeName,"x",50,0,false,bForce); + if ( !pType ) + pType = m_pTypeInfo; + } + else if ( bForce ) + _bNotConvert = false; + } + return pType; +} + +OUString OCopyTableWizard::createUniqueName(const OUString& _sName) +{ + OUString sName = _sName; + Sequence< OUString > aColumnNames( m_rSourceObject.getColumnNames() ); + if ( aColumnNames.hasElements() ) + sName = ::dbtools::createUniqueName( aColumnNames, sName, false ); + else + { + if ( m_vSourceColumns.find(sName) != m_vSourceColumns.end()) + { + sal_Int32 nPos = 0; + while(m_vSourceColumns.find(sName) != m_vSourceColumns.end()) + { + sName = _sName + OUString::number(++nPos); + } + } + } + return sName; +} + +void OCopyTableWizard::showColumnTypeNotSupported(std::u16string_view _rColumnName) +{ + OUString sMessage( DBA_RES( STR_UNKNOWN_TYPE_FOUND ) ); + sMessage = sMessage.replaceFirst("#1",_rColumnName); + showError(sMessage); +} + +void OCopyTableWizard::showError(const OUString& _sErrorMessage) +{ + SQLExceptionInfo aInfo(_sErrorMessage); + showError(aInfo.get()); +} + +void OCopyTableWizard::showError(const Any& _aError) +{ + if ( _aError.hasValue() && m_xInteractionHandler.is() ) + { + try + { + ::rtl::Reference< ::comphelper::OInteractionRequest > xRequest( new ::comphelper::OInteractionRequest( _aError ) ); + m_xInteractionHandler->handle( xRequest ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/misc/WExtendPages.cxx b/dbaccess/source/ui/misc/WExtendPages.cxx new file mode 100644 index 000000000..c7eac9181 --- /dev/null +++ b/dbaccess/source/ui/misc/WExtendPages.cxx @@ -0,0 +1,62 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <WExtendPages.hxx> +#include <RtfReader.hxx> +#include <HtmlReader.hxx> +#include <WCopyTable.hxx> + +using namespace com::sun::star; + +namespace dbaui +{ + +void OWizHTMLExtend::createReaderAndCallParser(sal_Int32 _nRows) +{ + tools::SvRef<OHTMLReader> xParser = new OHTMLReader(*m_pParserStream, + _nRows, + std::vector(m_pParent->GetColumnPositions()), + m_pParent->GetFormatter(), + m_pParent->GetComponentContext(), + &m_pParent->getDestVector(), + &m_pParent->getTypeInfo(), + m_pParent->shouldCreatePrimaryKey()); + xParser->CallParser(); +} + +void OWizRTFExtend::createReaderAndCallParser(sal_Int32 _nRows) +{ + tools::SvRef<ORTFReader> xParser = new ORTFReader(*m_pParserStream, + _nRows, + std::vector(m_pParent->GetColumnPositions()), + m_pParent->GetFormatter(), + m_pParent->GetComponentContext(), + &m_pParent->getDestVector(), + &m_pParent->getTypeInfo(), + m_pParent->shouldCreatePrimaryKey()); + xParser->CallParser(); +} + +void OWizNormalExtend::createReaderAndCallParser(sal_Int32 /*_nRows*/) +{ +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/misc/WNameMatch.cxx b/dbaccess/source/ui/misc/WNameMatch.cxx new file mode 100644 index 000000000..a6bb59da8 --- /dev/null +++ b/dbaccess/source/ui/misc/WNameMatch.cxx @@ -0,0 +1,330 @@ +/* -*- 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 <WNameMatch.hxx> +#include <osl/diagnose.h> +#include <FieldDescriptions.hxx> +#include <WCopyTable.hxx> +#include <core_resource.hxx> +#include <strings.hrc> +#include <bitmaps.hlst> +#include <com/sun/star/sdbc/DataType.hpp> + +using namespace ::dbaui; + +// OWizColumnSelect +OWizNameMatching::OWizNameMatching(weld::Container* pPage, OCopyTableWizard* pWizard) + : OWizardPage(pPage, pWizard, "dbaccess/ui/namematchingpage.ui", "NameMatching") + , m_xTABLE_LEFT(m_xBuilder->weld_label("leftlabel")) + , m_xTABLE_RIGHT(m_xBuilder->weld_label("rightlabel")) + , m_xCTRL_LEFT(m_xBuilder->weld_tree_view("left")) + , m_xCTRL_RIGHT(m_xBuilder->weld_tree_view("right")) + , m_xColumn_up(m_xBuilder->weld_button("up")) + , m_xColumn_down(m_xBuilder->weld_button("down")) + , m_xColumn_up_right(m_xBuilder->weld_button("up_right")) + , m_xColumn_down_right(m_xBuilder->weld_button("down_right")) + , m_xAll(m_xBuilder->weld_button("all")) + , m_xNone(m_xBuilder->weld_button("none")) +{ + OUString aImgUp(BMP_UP); + OUString aImgDown(BMP_DOWN); + m_xColumn_up->set_from_icon_name(aImgUp); + m_xColumn_down->set_from_icon_name(aImgDown); + m_xColumn_up_right->set_from_icon_name(aImgUp); + m_xColumn_down_right->set_from_icon_name(aImgDown); + + m_xColumn_up->connect_clicked(LINK(this,OWizNameMatching,ButtonClickHdl)); + m_xColumn_down->connect_clicked(LINK(this,OWizNameMatching,ButtonClickHdl)); + + m_xColumn_up_right->connect_clicked(LINK(this,OWizNameMatching,RightButtonClickHdl)); + m_xColumn_down_right->connect_clicked(LINK(this,OWizNameMatching,RightButtonClickHdl)); + + m_xAll->connect_clicked(LINK(this,OWizNameMatching,AllNoneClickHdl)); + m_xNone->connect_clicked(LINK(this,OWizNameMatching,AllNoneClickHdl)); + + m_xCTRL_LEFT->enable_toggle_buttons(weld::ColumnToggleType::Check); + + m_xCTRL_LEFT->connect_changed(LINK(this,OWizNameMatching,TableListClickHdl)); + m_xCTRL_RIGHT->connect_changed(LINK(this,OWizNameMatching,TableListRightSelectHdl)); + + m_sSourceText = m_xTABLE_LEFT->get_label() + "\n"; + m_sDestText = m_xTABLE_RIGHT->get_label() + "\n"; +} + +OWizNameMatching::~OWizNameMatching() +{ +} + +void OWizNameMatching::Reset() +{ + m_bFirstTime = false; +} + +void OWizNameMatching::Activate( ) +{ + // set source table name + OUString aName = m_sSourceText + m_pParent->m_sSourceName; + + m_xTABLE_LEFT->set_label(aName); + + // set dest table name + aName = m_sDestText + m_pParent->m_sName; + m_xTABLE_RIGHT->set_label(aName); + + FillListBox(*m_xCTRL_LEFT, m_pParent->getSrcVector(), true); + FillListBox(*m_xCTRL_RIGHT, m_pParent->getDestVector(), false); + + m_xColumn_up->set_sensitive( m_xCTRL_LEFT->n_children() > 1 ); + m_xColumn_down->set_sensitive( m_xCTRL_LEFT->n_children() > 1 ); + + m_xColumn_up_right->set_sensitive( m_xCTRL_RIGHT->n_children() > 1 ); + m_xColumn_down_right->set_sensitive( m_xCTRL_RIGHT->n_children() > 1 ); + + m_pParent->EnableNextButton(false); + m_xCTRL_LEFT->grab_focus(); + TableListClickHdl(*m_xCTRL_LEFT); +} + +bool OWizNameMatching::LeavePage() +{ + + const ODatabaseExport::TColumnVector& rSrcColumns = m_pParent->getSrcVector(); + + m_pParent->m_vColumnPositions.clear(); + m_pParent->m_vColumnTypes.clear(); + m_pParent->m_vColumnPositions.resize( rSrcColumns.size(), ODatabaseExport::TPositions::value_type( COLUMN_POSITION_NOT_FOUND, COLUMN_POSITION_NOT_FOUND ) ); + m_pParent->m_vColumnTypes.resize( rSrcColumns.size(), COLUMN_POSITION_NOT_FOUND ); + + std::unique_ptr<weld::TreeIter> xLeftEntry = m_xCTRL_LEFT->make_iterator(); + std::unique_ptr<weld::TreeIter> xRightEntry = m_xCTRL_RIGHT->make_iterator(); + + sal_Int32 nParamPos = 0; + bool bLeftEntry = m_xCTRL_LEFT->get_iter_first(*xLeftEntry); + bool bRightEntry = m_xCTRL_RIGHT->get_iter_first(*xRightEntry); + while (bLeftEntry && bRightEntry) + { + OFieldDescription* pSrcField = weld::fromId<OFieldDescription*>(m_xCTRL_LEFT->get_id(*xLeftEntry)); + OSL_ENSURE(pSrcField,"OWizNameMatching: OColumn can not be null!"); + + sal_Int32 nPos = 0; + for (auto const& column : rSrcColumns) + { + if (column->second == pSrcField) + break; + ++nPos; + } + + if (m_xCTRL_LEFT->get_toggle(*xLeftEntry) == TRISTATE_TRUE) + { + OFieldDescription* pDestField = weld::fromId<OFieldDescription*>(m_xCTRL_RIGHT->get_id(*xRightEntry)); + OSL_ENSURE(pDestField,"OWizNameMatching: OColumn can not be null!"); + const ODatabaseExport::TColumnVector& rDestColumns = m_pParent->getDestVector(); + sal_Int32 nPosDest = 1; + bool bDestColumnFound = false; + TOTypeInfoSP typeInfoSPFound; + for (auto const& column : rDestColumns) + { + if (column->second == pDestField) + { + bDestColumnFound = true; + typeInfoSPFound = column->second->getSpecialTypeInfo(); + break; + } + ++nPosDest; + } + + OSL_ENSURE((nPos) < static_cast<sal_Int32>(m_pParent->m_vColumnPositions.size()),"m_pParent->m_vColumnPositions: Illegal index for vector"); + m_pParent->m_vColumnPositions[nPos].first = ++nParamPos; + m_pParent->m_vColumnPositions[nPos].second = nPosDest; + + TOTypeInfoSP pTypeInfo; + + assert(bDestColumnFound); + if (bDestColumnFound) + { + bool bNotConvert = true; + pTypeInfo = m_pParent->convertType(typeInfoSPFound, bNotConvert); + } + + sal_Int32 nType = css::sdbc::DataType::VARCHAR; + if ( pTypeInfo ) + nType = pTypeInfo->nType; + m_pParent->m_vColumnTypes[nPos] = nType; + } + else + { + m_pParent->m_vColumnPositions[nPos].first = COLUMN_POSITION_NOT_FOUND; + m_pParent->m_vColumnPositions[nPos].second = COLUMN_POSITION_NOT_FOUND; + } + + bLeftEntry = m_xCTRL_LEFT->iter_next(*xLeftEntry); + bRightEntry = m_xCTRL_RIGHT->iter_next(*xRightEntry); + } + + return true; +} + +OUString OWizNameMatching::GetTitle() const { return DBA_RES(STR_WIZ_NAME_MATCHING_TITLE); } + +IMPL_LINK(OWizNameMatching, ButtonClickHdl, weld::Button&, rButton, void) +{ + int nPos = m_xCTRL_LEFT->get_selected_index(); + if (nPos == -1) + return; + + int nOrigPos = nPos; + if (&rButton == m_xColumn_up.get() && nPos) + --nPos; + else if (&rButton == m_xColumn_down.get() && nPos < m_xCTRL_LEFT->n_children() - 1) + ++nPos; + + m_xCTRL_LEFT->swap(nOrigPos, nPos); + + m_xCTRL_LEFT->scroll_to_row(nPos); + + TableListClickHdl(*m_xCTRL_LEFT); +} + +IMPL_LINK( OWizNameMatching, RightButtonClickHdl, weld::Button&, rButton, void ) +{ + int nPos = m_xCTRL_RIGHT->get_selected_index(); + if (nPos == -1) + return; + + int nOrigPos = nPos; + if (&rButton == m_xColumn_up_right.get() && nPos) + --nPos; + else if (&rButton == m_xColumn_down_right.get() && nPos < m_xCTRL_RIGHT->n_children() - 1) + ++nPos; + + m_xCTRL_RIGHT->swap(nOrigPos, nPos); + + m_xCTRL_RIGHT->scroll_to_row(nPos); + + TableListRightSelectHdl(*m_xCTRL_RIGHT); +} + +namespace +{ + int GetFirstEntryInView(weld::TreeView& rTreeView) + { + int nFirstEntryInView = -1; + + rTreeView.visible_foreach([&nFirstEntryInView, &rTreeView](weld::TreeIter& rEntry){ + nFirstEntryInView = rTreeView.get_iter_index_in_parent(rEntry); + // stop after first entry + return true; + }); + + return nFirstEntryInView; + } +} + +IMPL_LINK_NOARG(OWizNameMatching, TableListClickHdl, weld::TreeView&, void) +{ + int nPos = m_xCTRL_LEFT->get_selected_index(); + if (nPos == -1) + return; + + int nOldEntry = m_xCTRL_RIGHT->get_selected_index(); + if (nOldEntry != -1 && nPos != nOldEntry) + { + m_xCTRL_RIGHT->unselect(nOldEntry); + if (nPos < m_xCTRL_RIGHT->n_children()) + { + int nNewPos = GetFirstEntryInView(*m_xCTRL_LEFT); + if ( nNewPos - nPos == 1 ) + --nNewPos; + m_xCTRL_RIGHT->scroll_to_row(nNewPos); + m_xCTRL_RIGHT->select(nPos); + } + } + else if (nOldEntry == -1) + { + if (nPos < m_xCTRL_RIGHT->n_children()) + m_xCTRL_RIGHT->select(nPos); + } +} + +IMPL_LINK_NOARG( OWizNameMatching, TableListRightSelectHdl, weld::TreeView&, void ) +{ + int nPos = m_xCTRL_RIGHT->get_selected_index(); + if (nPos == -1) + return; + + OFieldDescription* pColumn = weld::fromId<OFieldDescription*>(m_xCTRL_RIGHT->get_id(nPos)); + if (pColumn->IsAutoIncrement()) + { + m_xCTRL_RIGHT->unselect(nPos); + return; + } + + int nOldEntry = m_xCTRL_LEFT->get_selected_index(); + if (nOldEntry != -1 && nPos != nOldEntry) + { + m_xCTRL_LEFT->unselect(nOldEntry); + if (nPos < m_xCTRL_LEFT->n_children()) + { + int nNewPos = GetFirstEntryInView(*m_xCTRL_RIGHT); + if ( nNewPos - nPos == 1 ) + nNewPos--; + m_xCTRL_LEFT->scroll_to_row(nNewPos); + m_xCTRL_LEFT->select(nPos); + } + } + else if (nOldEntry == -1) + { + if (nPos < m_xCTRL_LEFT->n_children()) + m_xCTRL_LEFT->select(nPos); + } +} + +IMPL_LINK(OWizNameMatching, AllNoneClickHdl, weld::Button&, rButton, void) +{ + bool bAll = &rButton == m_xAll.get(); + m_xCTRL_LEFT->all_foreach([this, bAll](weld::TreeIter& rEntry){ + m_xCTRL_LEFT->set_toggle(rEntry, bAll ? TRISTATE_TRUE : TRISTATE_FALSE); + return false; + }); +} + +void OWizNameMatching::FillListBox(weld::TreeView& rTreeView, const ODatabaseExport::TColumnVector& rList, bool bCheckButtons) +{ + rTreeView.clear(); + + int nRow(0); + + for (auto const& elem : rList) + { + rTreeView.append(); + if (bCheckButtons) + { + bool bChecked = !elem->second->IsAutoIncrement(); + rTreeView.set_toggle(nRow, bChecked ? TRISTATE_TRUE : TRISTATE_FALSE); + } + rTreeView.set_text(nRow, elem->first, 0); + rTreeView.set_id(nRow, weld::toId(elem->second)); + ++nRow; + } + + if (rTreeView.n_children()) + rTreeView.select(0); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/misc/WTypeSelect.cxx b/dbaccess/source/ui/misc/WTypeSelect.cxx new file mode 100644 index 000000000..d5462ed3f --- /dev/null +++ b/dbaccess/source/ui/misc/WTypeSelect.cxx @@ -0,0 +1,417 @@ +/* -*- 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 <WTypeSelect.hxx> +#include <bitmaps.hlst> +#include <tools/diagnose_ex.h> +#include <osl/diagnose.h> +#include <FieldDescriptions.hxx> +#include <WCopyTable.hxx> +#include <strings.hrc> +#include <tools/stream.hxx> +#include <vcl/commandevent.hxx> +#include <vcl/svapp.hxx> +#include <UITools.hxx> +#include <core_resource.hxx> +#include <FieldControls.hxx> + +using namespace ::dbaui; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::sdbc; + +// OWizTypeSelectControl +OWizTypeSelectControl::OWizTypeSelectControl(weld::Container* pPage, OWizTypeSelect* pParentTabPage) + : OFieldDescControl(pPage, nullptr) + , m_pParentTabPage(pParentTabPage) +{ +} + +OWizTypeSelectControl::~OWizTypeSelectControl() +{ +} + +void OWizTypeSelectControl::ActivateAggregate( EControlType eType ) +{ + switch(eType ) + { + case tpFormat: + case tpDefault: + case tpAutoIncrement: + case tpAutoIncrementValue: + break; + default: + OFieldDescControl::ActivateAggregate( eType ); + } +} + +void OWizTypeSelectControl::DeactivateAggregate( EControlType eType ) +{ + switch(eType ) + { + case tpFormat: + case tpDefault: + case tpAutoIncrement: + case tpAutoIncrementValue: + break; + default: + OFieldDescControl::DeactivateAggregate( eType ); + } +} + +void OWizTypeSelectControl::CellModified(sal_Int32 nRow, sal_uInt16 nColId ) +{ + OSL_ENSURE(nRow == -1,"nRow must be -1!"); + + weld::TreeView* pListBox = m_pParentTabPage->m_xColumnNames->GetWidget(); + + OFieldDescription* pCurFieldDescr = getCurrentFieldDescData(); + + const sal_Int32 nPos = pListBox->find_text(pCurFieldDescr->GetName()); + pCurFieldDescr = weld::fromId<OFieldDescription*>(pListBox->get_id(nPos)); + OSL_ENSURE( pCurFieldDescr, "OWizTypeSelectControl::CellModified: Columnname/type not found in the listbox!" ); + if ( !pCurFieldDescr ) + return; + setCurrentFieldDescData( pCurFieldDescr ); + + OUString sName = pCurFieldDescr->GetName(); + OUString sNewName; + const OPropColumnEditCtrl* pColumnName = getColumnCtrl(); + if ( pColumnName ) + sNewName = pColumnName->get_text(); + + switch(nColId) + { + case FIELD_PROPERTY_COLUMNNAME: + { + OCopyTableWizard* pWiz = m_pParentTabPage->m_pParent; + // first we have to check if this name already exists + bool bDoubleName = false; + bool bCase = true; + if ( getMetaData().is() && !getMetaData()->supportsMixedCaseQuotedIdentifiers() ) + { + bCase = false; + const sal_Int32 nCount = pListBox->n_children(); + for (sal_Int32 i=0 ; !bDoubleName && i < nCount ; ++i) + { + OUString sEntry(pListBox->get_text(i)); + bDoubleName = sNewName.equalsIgnoreAsciiCase(sEntry); + } + if ( !bDoubleName && pWiz->shouldCreatePrimaryKey() ) + bDoubleName = sNewName.equalsIgnoreAsciiCase(pWiz->getPrimaryKeyName()); + + } + else + bDoubleName = ((pListBox->find_text(sNewName) != -1) + || ( pWiz->shouldCreatePrimaryKey() + && pWiz->getPrimaryKeyName() == sNewName) ); + + if ( bDoubleName ) + { + OUString strMessage = DBA_RES(STR_TABLEDESIGN_DUPLICATE_NAME); + strMessage = strMessage.replaceFirst("$column$", sNewName); + pWiz->showError(strMessage); + pCurFieldDescr->SetName(sName); + DisplayData(pCurFieldDescr); + m_pParentTabPage->setDuplicateName(true); + return; + } + + OUString sOldName = pCurFieldDescr->GetName(); + pCurFieldDescr->SetName(sNewName); + m_pParentTabPage->setDuplicateName(false); + + // now we change the name + + ::comphelper::UStringMixEqual aCase(bCase); + for (auto & elem : pWiz->m_mNameMapping) + { + if ( aCase(elem.second,sName) ) + { + elem.second = sNewName; + break; + } + } + + pListBox->remove(nPos); + pListBox->insert_text(nPos, pCurFieldDescr->GetName()); + pListBox->set_id(nPos, weld::toId(pCurFieldDescr)); + + pWiz->replaceColumn(nPos,pCurFieldDescr,sOldName); + } + break; + } + saveCurrentFieldDescData(); +} + +css::lang::Locale OWizTypeSelectControl::GetLocale() const +{ + return m_pParentTabPage->m_pParent->GetLocale(); +} + +Reference< XNumberFormatter > OWizTypeSelectControl::GetFormatter() const +{ + return m_pParentTabPage->m_pParent->GetFormatter(); +} + +TOTypeInfoSP OWizTypeSelectControl::getTypeInfo(sal_Int32 _nPos) +{ + return m_pParentTabPage->m_pParent->getDestTypeInfo(_nPos); +} + +const OTypeInfoMap* OWizTypeSelectControl::getTypeInfo() const +{ + return &m_pParentTabPage->m_pParent->getDestTypeInfo(); +} + +css::uno::Reference< css::sdbc::XDatabaseMetaData> OWizTypeSelectControl::getMetaData() +{ + return m_pParentTabPage->m_pParent->m_xDestConnection->getMetaData(); +} + +css::uno::Reference< css::sdbc::XConnection> OWizTypeSelectControl::getConnection() +{ + return m_pParentTabPage->m_pParent->m_xDestConnection; +} + +bool OWizTypeSelectControl::isAutoIncrementValueEnabled() const +{ + return m_pParentTabPage->m_bAutoIncrementEnabled; +} + +OUString OWizTypeSelectControl::getAutoIncrementValue() const +{ + return m_pParentTabPage->m_sAutoIncrementValue; +} + +OWizTypeSelect::OWizTypeSelect(weld::Container* pPage, OCopyTableWizard* pWizard, SvStream* pStream) + : OWizardPage(pPage, pWizard, "dbaccess/ui/typeselectpage.ui", "TypeSelect") + , m_xColumnNames(new OWizTypeSelectList(m_xBuilder->weld_tree_view("columnnames"))) + , m_xColumns(m_xBuilder->weld_label("columns")) + , m_xControlContainer(m_xBuilder->weld_container("control_container")) + , m_xTypeControl(new OWizTypeSelectControl(m_xControlContainer.get(), this)) + , m_xAutoType(m_xBuilder->weld_label("autotype")) + , m_xAutoFt(m_xBuilder->weld_label("autolabel")) + , m_xAutoEt(m_xBuilder->weld_spin_button("auto")) + , m_xAutoPb(m_xBuilder->weld_button("autobutton")) + , m_pParserStream(pStream) + , m_nDisplayRow(0) + , m_bAutoIncrementEnabled(false) + , m_bDuplicateName(false) +{ + m_xColumnNames->connect_changed(LINK(this,OWizTypeSelect,ColumnSelectHdl)); + + m_xTypeControl->Init(); + + m_xAutoEt->set_text("10"); + m_xAutoEt->set_digits(0); + m_xAutoPb->connect_clicked(LINK(this,OWizTypeSelect,ButtonClickHdl)); + m_xColumnNames->set_selection_mode(SelectionMode::Multiple); + + try + { + m_xColumnNames->SetPKey( m_pParent->supportsPrimaryKey() ); + ::dbaui::fillAutoIncrementValue( m_pParent->m_xDestConnection, m_bAutoIncrementEnabled, m_sAutoIncrementValue ); + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +OWizTypeSelect::~OWizTypeSelect() +{ +} + +OUString OWizTypeSelect::GetTitle() const +{ + return DBA_RES(STR_WIZ_TYPE_SELECT_TITLE); +} + +IMPL_LINK_NOARG(OWizTypeSelect, ColumnSelectHdl, weld::TreeView&, void) +{ + OFieldDescription* pField = weld::fromId<OFieldDescription*>(m_xColumnNames->get_selected_id()); + if (pField) + m_xTypeControl->DisplayData(pField); + + m_xTypeControl->Enable(m_xColumnNames->count_selected_rows() == 1); +} + +void OWizTypeSelect::Reset() +{ + // restore original state + m_xColumnNames->clear(); + sal_Int32 nCount(0), nBreakPos; + m_pParent->CheckColumns(nBreakPos); + + const ODatabaseExport::TColumnVector& rDestColumns = m_pParent->getDestVector(); + for (auto const& column : rDestColumns) + { + OUString sId(weld::toId(column->second)); + m_xColumnNames->append(sId, column->first); + if (column->second->IsPrimaryKey()) + m_xColumnNames->set_image(nCount, BMP_PRIMARY_KEY); + ++nCount; + } + m_bFirstTime = false; +} + +void OWizTypeSelect::Activate( ) +{ + bool bOldFirstTime = m_bFirstTime; + Reset(); + m_bFirstTime = bOldFirstTime; + + m_xColumnNames->select(m_nDisplayRow); + m_nDisplayRow = 0; + ColumnSelectHdl(*m_xColumnNames->GetWidget()); +} + +bool OWizTypeSelect::LeavePage() +{ + bool bDuplicateName = false; + OFieldDescription* pField = weld::fromId<OFieldDescription*>(m_xColumnNames->get_selected_id()); + if ( pField ) + { + m_xTypeControl->SaveData(pField); + bDuplicateName = m_bDuplicateName; + } + return !bDuplicateName; +} + +void OWizTypeSelect::EnableAuto(bool bEnable) +{ + m_xAutoFt->set_visible(bEnable); + m_xAutoEt->set_visible(bEnable); + m_xAutoPb->set_visible(bEnable); + m_xAutoType->set_visible(bEnable); +} + +IMPL_LINK_NOARG(OWizTypeSelect, ButtonClickHdl, weld::Button&, void) +{ + sal_Int32 nBreakPos; + m_pParent->CheckColumns(nBreakPos); + + // fill column list + sal_uInt32 nRows = m_xAutoEt->get_text().toInt32(); + if(m_pParserStream) + { + sal_uInt64 const nTell = m_pParserStream->Tell(); // might change seek position of stream + + createReaderAndCallParser(nRows); + m_pParserStream->Seek(nTell); + } + + Activate(); +} + +OWizTypeSelectList::OWizTypeSelectList(std::unique_ptr<weld::TreeView> xControl) + : m_xControl(std::move(xControl)) + , m_bPKey(false) +{ + m_xControl->connect_popup_menu(LINK(this, OWizTypeSelectList, CommandHdl)); +} + +bool OWizTypeSelectList::IsPrimaryKeyAllowed() const +{ + auto aRows = m_xControl->get_selected_rows(); + std::sort(aRows.begin(), aRows.end()); + + const sal_Int32 nCount = aRows.size(); + + for( sal_Int32 j = 0; m_bPKey && j < nCount; ++j ) + { + OFieldDescription* pField = weld::fromId<OFieldDescription*>(m_xControl->get_id(aRows[j])); + if(!pField || pField->getTypeInfo()->nSearchType == ColumnSearch::NONE) + return false; + } + return true; +} + +void OWizTypeSelectList::setPrimaryKey(OFieldDescription* _pFieldDescr, sal_uInt16 _nPos, bool _bSet) +{ + _pFieldDescr->SetPrimaryKey(_bSet); + if( _bSet ) + { + m_xControl->set_image(_nPos, BMP_PRIMARY_KEY); + } + else if( _pFieldDescr->getTypeInfo()->bNullable ) + { + _pFieldDescr->SetControlDefault(Any()); + m_xControl->set_image(_nPos, OUString()); + } +} + +IMPL_LINK(OWizTypeSelectList, CommandHdl, const CommandEvent&, rCEvt, bool) +{ + if (rCEvt.GetCommand() != CommandEventId::ContextMenu) + return false; + if (!IsPrimaryKeyAllowed()) + return false; + + std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(m_xControl.get(), "dbaccess/ui/keymenu.ui")); + auto xContextMenu = xBuilder->weld_menu("menu"); + // Should primary key checkbox be checked? + const sal_Int32 nCount = m_xControl->n_children(); + bool bCheckOk = false; + for(sal_Int32 j = 0 ; j < nCount ; ++j) + { + OFieldDescription* pFieldDescr = weld::fromId<OFieldDescription*>(m_xControl->get_id(j)); + // if at least one of the fields is selected but not in the primary key, + // or is in the primary key but not selected, then don't check the + // primary key checkbox. + if( pFieldDescr && pFieldDescr->IsPrimaryKey() != m_xControl->is_selected(j) ) + { + bCheckOk = false; + break; + } + if (!bCheckOk && m_xControl->is_selected(j)) + bCheckOk = true; + } + + if (bCheckOk) + xContextMenu->set_active("primarykey", true); + + OString sCommand(xContextMenu->popup_at_rect(m_xControl.get(), tools::Rectangle(rCEvt.GetMousePosPixel(), Size(1,1)))); + if (sCommand != "primarykey") + return true; + + for (sal_Int32 j = 0 ; j < nCount; ++j) + { + OFieldDescription* pFieldDescr = weld::fromId<OFieldDescription*>(m_xControl->get_id(j)); + if (pFieldDescr) + { + if(!bCheckOk && m_xControl->is_selected(j)) + { + setPrimaryKey(pFieldDescr,j,true); + } + else + { + setPrimaryKey(pFieldDescr,j); + } + } + } + m_aChangeHdl.Call(*m_xControl); + + return true; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/misc/asyncmodaldialog.cxx b/dbaccess/source/ui/misc/asyncmodaldialog.cxx new file mode 100644 index 000000000..3c59a58f8 --- /dev/null +++ b/dbaccess/source/ui/misc/asyncmodaldialog.cxx @@ -0,0 +1,91 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <asyncmodaldialog.hxx> + +#include <com/sun/star/lang/IllegalArgumentException.hpp> + +#include <vcl/svapp.hxx> +#include <tools/diagnose_ex.h> + +namespace dbaui +{ + + using ::com::sun::star::uno::Reference; + using ::com::sun::star::ui::dialogs::XExecutableDialog; + using ::com::sun::star::lang::IllegalArgumentException; + using ::com::sun::star::uno::Exception; + + namespace { + + // AsyncDialogExecutor + class DialogExecutor_Impl + { + Reference< XExecutableDialog > m_xDialog; + + public: + explicit DialogExecutor_Impl( const Reference< XExecutableDialog >& _rxDialog ) + :m_xDialog( _rxDialog ) + { + } + + void execute() + { + Application::PostUserEvent( LINK( this, DialogExecutor_Impl, onExecute ) ); + } + + protected: + ~DialogExecutor_Impl() + { + } + + private: + DECL_LINK( onExecute, void*, void ); + }; + + } + + IMPL_LINK_NOARG( DialogExecutor_Impl, onExecute, void*, void ) + { + try + { + m_xDialog->execute(); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + delete this; + } + + // AsyncDialogExecutor + void AsyncDialogExecutor::executeModalDialogAsync( const Reference< XExecutableDialog >& _rxDialog ) + { + if ( !_rxDialog.is() ) + throw IllegalArgumentException(); + + DialogExecutor_Impl* pExecutor = new DialogExecutor_Impl( _rxDialog ); + pExecutor->execute(); + // will delete itself + } + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/misc/charsets.cxx b/dbaccess/source/ui/misc/charsets.cxx new file mode 100644 index 000000000..546d21cb0 --- /dev/null +++ b/dbaccess/source/ui/misc/charsets.cxx @@ -0,0 +1,130 @@ +/* -*- 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 <charsets.hxx> +#include <core_resource.hxx> +#include <osl/diagnose.h> +#include <strings.hrc> +#include <rtl/tencinfo.h> +#include <svx/txenctab.hxx> + +namespace dbaui +{ + using namespace ::dbtools; + + // OCharsetDisplay + OCharsetDisplay::OCharsetDisplay() + : m_aSystemDisplayName(DBA_RES( STR_RSC_CHARSETS )) + { + } + + bool OCharsetDisplay::approveEncoding( const rtl_TextEncoding _eEncoding, const rtl_TextEncodingInfo& _rInfo ) const + { + if ( !OCharsetMap::approveEncoding( _eEncoding, _rInfo ) ) + return false; + + if ( RTL_TEXTENCODING_DONTKNOW == _eEncoding ) + return true; + + return !SvxTextEncodingTable::GetTextString(_eEncoding).isEmpty(); + } + + OCharsetDisplay::const_iterator OCharsetDisplay::begin() const + { + return const_iterator( this, OCharsetMap::begin() ); + } + + OCharsetDisplay::const_iterator OCharsetDisplay::end() const + { + return const_iterator( this, OCharsetMap::end() ); + } + + OCharsetDisplay::const_iterator OCharsetDisplay::findEncoding(const rtl_TextEncoding _eEncoding) const + { + OCharsetMap::const_iterator aBaseIter = OCharsetMap::find(_eEncoding); + return const_iterator( this, aBaseIter ); + } + + OCharsetDisplay::const_iterator OCharsetDisplay::findIanaName(const OUString& _rIanaName) const + { + OCharsetMap::const_iterator aBaseIter = OCharsetMap::findIanaName(_rIanaName); + return const_iterator( this, aBaseIter ); + } + + OCharsetDisplay::const_iterator OCharsetDisplay::findDisplayName(const OUString& _rDisplayName) const + { + rtl_TextEncoding eEncoding = RTL_TEXTENCODING_DONTKNOW; + if ( _rDisplayName != m_aSystemDisplayName ) + { + eEncoding = SvxTextEncodingTable::GetTextEncoding(_rDisplayName); + OSL_ENSURE( RTL_TEXTENCODING_DONTKNOW != eEncoding, + "OCharsetDisplay::find: non-empty display name, but DONTKNOW!" ); + } + return const_iterator( this, OCharsetMap::find( eEncoding ) ); + } + + // CharsetDisplayDerefHelper + CharsetDisplayDerefHelper::CharsetDisplayDerefHelper(const CharsetDisplayDerefHelper& _rSource) + :CharsetDisplayDerefHelper_Base(_rSource) + ,m_sDisplayName(_rSource.m_sDisplayName) + { + } + + CharsetDisplayDerefHelper::CharsetDisplayDerefHelper(const ::dbtools::CharsetIteratorDerefHelper& _rBase, const OUString& _rDisplayName) + :CharsetDisplayDerefHelper_Base(_rBase) + ,m_sDisplayName(_rDisplayName) + { + OSL_ENSURE( !m_sDisplayName.isEmpty(), "CharsetDisplayDerefHelper::CharsetDisplayDerefHelper: invalid display name!" ); + } + + // OCharsetDisplay::ExtendedCharsetIterator + OCharsetDisplay::ExtendedCharsetIterator::ExtendedCharsetIterator( const OCharsetDisplay* _pContainer, const base_iterator& _rPosition ) + :m_pContainer(_pContainer) + ,m_aPosition(_rPosition) + { + OSL_ENSURE(m_pContainer, "OCharsetDisplay::ExtendedCharsetIterator::ExtendedCharsetIterator : invalid container!"); + } + + CharsetDisplayDerefHelper OCharsetDisplay::ExtendedCharsetIterator::operator*() const + { + OSL_ENSURE( m_aPosition != m_pContainer->OCharsetDisplay_Base::end(), "OCharsetDisplay::ExtendedCharsetIterator::operator* : invalid position!"); + + rtl_TextEncoding eEncoding = (*m_aPosition).getEncoding(); + return CharsetDisplayDerefHelper( + *m_aPosition, + RTL_TEXTENCODING_DONTKNOW == eEncoding ? m_pContainer->m_aSystemDisplayName : SvxTextEncodingTable::GetTextString(eEncoding) + ); + } + + const OCharsetDisplay::ExtendedCharsetIterator& OCharsetDisplay::ExtendedCharsetIterator::operator++() + { + OSL_ENSURE( m_aPosition != m_pContainer->OCharsetDisplay_Base::end(), "OCharsetDisplay::ExtendedCharsetIterator::operator++ : invalid position!"); + if ( m_aPosition != m_pContainer->OCharsetDisplay_Base::end() ) + ++m_aPosition; + return *this; + } + + bool operator==(const OCharsetDisplay::ExtendedCharsetIterator& lhs, const OCharsetDisplay::ExtendedCharsetIterator& rhs) + { + return (lhs.m_pContainer == rhs.m_pContainer) && (lhs.m_aPosition == rhs.m_aPosition); + } + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/misc/controllerframe.cxx b/dbaccess/source/ui/misc/controllerframe.cxx new file mode 100644 index 000000000..3634a56eb --- /dev/null +++ b/dbaccess/source/ui/misc/controllerframe.cxx @@ -0,0 +1,390 @@ +/* -*- 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 <dbaccess/controllerframe.hxx> +#include <dbaccess/IController.hxx> + +#include <com/sun/star/awt/XTopWindow.hpp> +#include <com/sun/star/awt/XWindow2.hpp> +#include <com/sun/star/lang/DisposedException.hpp> +#include <com/sun/star/document/XDocumentEventBroadcaster.hpp> +#include <com/sun/star/frame/XController2.hpp> + +#include <cppuhelper/implbase.hxx> +#include <rtl/ref.hxx> +#include <sfx2/objsh.hxx> +#include <tools/diagnose_ex.h> +#include <toolkit/helper/vclunohelper.hxx> +#include <vcl/window.hxx> + +namespace dbaui +{ + + using ::com::sun::star::uno::Reference; + using ::com::sun::star::uno::XInterface; + using ::com::sun::star::uno::UNO_QUERY; + using ::com::sun::star::uno::UNO_QUERY_THROW; + using ::com::sun::star::uno::UNO_SET_THROW; + using ::com::sun::star::uno::Exception; + using ::com::sun::star::uno::RuntimeException; + using ::com::sun::star::uno::Any; + using ::com::sun::star::frame::XFrame; + using ::com::sun::star::frame::FrameAction; + using ::com::sun::star::frame::FrameAction_FRAME_ACTIVATED; + using ::com::sun::star::frame::FrameAction_FRAME_UI_ACTIVATED; + using ::com::sun::star::frame::FrameAction_FRAME_DEACTIVATING; + using ::com::sun::star::frame::FrameAction_FRAME_UI_DEACTIVATING; + using ::com::sun::star::frame::XModel; + using ::com::sun::star::frame::XController; + using ::com::sun::star::frame::XController2; + using ::com::sun::star::awt::XTopWindow; + using ::com::sun::star::awt::XTopWindowListener; + using ::com::sun::star::awt::XWindow2; + using ::com::sun::star::lang::DisposedException; + using ::com::sun::star::lang::EventObject; + using ::com::sun::star::document::XDocumentEventBroadcaster; + using ::com::sun::star::awt::XWindow; + + // FrameWindowActivationListener + typedef ::cppu::WeakImplHelper< XTopWindowListener + > FrameWindowActivationListener_Base; + + namespace { + + class FrameWindowActivationListener : public FrameWindowActivationListener_Base + { + public: + explicit FrameWindowActivationListener( ControllerFrame_Data& _rData ); + + void dispose(); + + protected: + virtual ~FrameWindowActivationListener() override; + + // XTopWindowListener + virtual void SAL_CALL windowOpened( const css::lang::EventObject& e ) override; + virtual void SAL_CALL windowClosing( const css::lang::EventObject& e ) override; + virtual void SAL_CALL windowClosed( const css::lang::EventObject& e ) override; + virtual void SAL_CALL windowMinimized( const css::lang::EventObject& e ) override; + virtual void SAL_CALL windowNormalized( const css::lang::EventObject& e ) override; + virtual void SAL_CALL windowActivated( const css::lang::EventObject& e ) override; + virtual void SAL_CALL windowDeactivated( const css::lang::EventObject& e ) override; + + // XEventListener + virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override; + + private: + void impl_checkDisposed_throw() const; + void impl_registerOnFrameContainerWindow_nothrow( bool _bRegister ); + + private: + ControllerFrame_Data* m_pData; + }; + + } + + // ControllerFrame_Data + struct ControllerFrame_Data + { + explicit ControllerFrame_Data( IController& _rController ) + :m_rController( _rController ) + ,m_bActive( false ) + ,m_bIsTopLevelDocumentWindow( false ) + { + } + + IController& m_rController; + Reference< XFrame > m_xFrame; + Reference< XDocumentEventBroadcaster > m_xDocEventBroadcaster; + ::rtl::Reference< FrameWindowActivationListener > m_pListener; + bool m_bActive; + bool m_bIsTopLevelDocumentWindow; + }; + + // helper + static void lcl_setFrame_nothrow( ControllerFrame_Data& _rData, const Reference< XFrame >& _rxFrame ) + { + // release old listener + if (_rData.m_pListener) + { + _rData.m_pListener->dispose(); + _rData.m_pListener = nullptr; + } + + // remember new frame + _rData.m_xFrame = _rxFrame; + + // create new listener + if ( _rData.m_xFrame.is() ) + _rData.m_pListener = new FrameWindowActivationListener( _rData ); + + // at this point in time, we can assume the controller also has a model set, if it supports models + try + { + Reference< XController > xController( _rData.m_rController.getXController(), UNO_SET_THROW ); + Reference< XModel > xModel( xController->getModel() ); + if ( xModel.is() ) + _rData.m_xDocEventBroadcaster.set( xModel, UNO_QUERY ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + + static bool lcl_isActive_nothrow( const Reference< XFrame >& _rxFrame ) + { + bool bIsActive = false; + try + { + if ( _rxFrame.is() ) + { + Reference< XWindow2 > xWindow( _rxFrame->getContainerWindow(), UNO_QUERY_THROW ); + bIsActive = xWindow->isActive(); + } + + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + return bIsActive; + } + + /** updates various global and local states with a new active component + + In particular, the following are updated + * the global working document (aka Basic's ThisComponent in the application + Basic), with our controller's model, or the controller itself if there is no such + model. + */ + static void lcl_updateActiveComponents_nothrow( const ControllerFrame_Data& _rData ) + { + try + { + Reference< XController > xCompController( _rData.m_rController.getXController() ); + OSL_ENSURE( xCompController.is(), "lcl_updateActiveComponents_nothrow: can't do anything without a controller!" ); + if ( !xCompController.is() ) + return; + + if ( _rData.m_bActive && _rData.m_bIsTopLevelDocumentWindow ) + { + // set the "current component" at the SfxObjectShell + Reference< XModel > xModel( xCompController->getModel() ); + Reference< XInterface > xCurrentComponent; + if ( xModel.is() ) + xCurrentComponent = xModel; + else + xCurrentComponent = xCompController; + SfxObjectShell::SetCurrentComponent( xCurrentComponent ); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + + /** broadcasts the OnFocus resp. OnUnfocus event + */ + static void lcl_notifyFocusChange_nothrow( ControllerFrame_Data& _rData, bool _bActive ) + { + try + { + if ( _rData.m_xDocEventBroadcaster.is() ) + { + OUString sEventName = _bActive ? OUString("OnFocus") : OUString("OnUnfocus"); + Reference< XController2 > xController( _rData.m_rController.getXController(), UNO_QUERY_THROW ); + _rData.m_xDocEventBroadcaster->notifyDocumentEvent( sEventName, xController, Any() ); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + + static void lcl_updateActive_nothrow( ControllerFrame_Data& _rData, bool _bActive ) + { + if ( _rData.m_bActive == _bActive ) + return; + _rData.m_bActive = _bActive; + + lcl_updateActiveComponents_nothrow( _rData ); + lcl_notifyFocusChange_nothrow( _rData, _bActive ); + } + + FrameWindowActivationListener::FrameWindowActivationListener( ControllerFrame_Data& _rData ) + :m_pData( &_rData ) + { + impl_registerOnFrameContainerWindow_nothrow( true ); + } + + FrameWindowActivationListener::~FrameWindowActivationListener() + { + } + + void FrameWindowActivationListener::dispose() + { + impl_registerOnFrameContainerWindow_nothrow( false ); + m_pData = nullptr; + } + + void FrameWindowActivationListener::impl_registerOnFrameContainerWindow_nothrow( bool _bRegister ) + { + OSL_ENSURE( m_pData && m_pData->m_xFrame.is(), "FrameWindowActivationListener::impl_registerOnFrameContainerWindow_nothrow: no frame!" ); + if ( !m_pData || !m_pData->m_xFrame.is() ) + return; + + try + { + void ( SAL_CALL XTopWindow::*pListenerAction )( const Reference< XTopWindowListener >& ) = + _bRegister ? &XTopWindow::addTopWindowListener : &XTopWindow::removeTopWindowListener; + + const Reference< XWindow > xContainerWindow( m_pData->m_xFrame->getContainerWindow(), UNO_SET_THROW ); + if ( _bRegister ) + { + const vcl::Window* pContainerWindow = VCLUnoHelper::GetWindow( xContainerWindow ); + ENSURE_OR_THROW( pContainerWindow, "no Window implementation for the frame's container window!" ); + + m_pData->m_bIsTopLevelDocumentWindow = bool( pContainerWindow->GetExtendedStyle() & WindowExtendedStyle::Document ); + } + + const Reference< XTopWindow > xFrameContainer( xContainerWindow, UNO_QUERY ); + if ( xFrameContainer.is() ) + (xFrameContainer.get()->*pListenerAction)( this ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + + void FrameWindowActivationListener::impl_checkDisposed_throw() const + { + if ( !m_pData ) + throw DisposedException( OUString(), *const_cast< FrameWindowActivationListener* >( this ) ); + } + + void SAL_CALL FrameWindowActivationListener::windowOpened( const EventObject& /*_rEvent*/ ) + { + // not interested in + } + + void SAL_CALL FrameWindowActivationListener::windowClosing( const EventObject& /*_rEvent*/ ) + { + // not interested in + } + + void SAL_CALL FrameWindowActivationListener::windowClosed( const EventObject& /*_rEvent*/ ) + { + // not interested in + } + + void SAL_CALL FrameWindowActivationListener::windowMinimized( const EventObject& /*_rEvent*/ ) + { + // not interested in + } + + void SAL_CALL FrameWindowActivationListener::windowNormalized( const EventObject& /*_rEvent*/ ) + { + // not interested in + } + + void SAL_CALL FrameWindowActivationListener::windowActivated( const EventObject& /*_rEvent*/ ) + { + impl_checkDisposed_throw(); + lcl_updateActive_nothrow( *m_pData, true ); + } + + void SAL_CALL FrameWindowActivationListener::windowDeactivated( const EventObject& /*_rEvent*/ ) + { + impl_checkDisposed_throw(); + lcl_updateActive_nothrow( *m_pData, false ); + } + + void SAL_CALL FrameWindowActivationListener::disposing( const EventObject& /*_rEvent*/ ) + { + dispose(); + } + + // ControllerFrame + ControllerFrame::ControllerFrame( IController& _rController ) + :m_pData( new ControllerFrame_Data( _rController ) ) + { + } + + ControllerFrame::~ControllerFrame() + { + } + + const Reference< XFrame >& ControllerFrame::attachFrame( const Reference< XFrame >& _rxFrame ) + { + // set new frame, including listener handling + lcl_setFrame_nothrow( *m_pData, _rxFrame ); + + // determine whether we're active + m_pData->m_bActive = lcl_isActive_nothrow( m_pData->m_xFrame ); + + // update active component + if ( m_pData->m_bActive ) + { + lcl_updateActiveComponents_nothrow( *m_pData ); + lcl_notifyFocusChange_nothrow( *m_pData, true ); + } + + return m_pData->m_xFrame; + } + + const Reference< XFrame >& ControllerFrame::getFrame() const + { + return m_pData->m_xFrame; + } + + bool ControllerFrame::isActive() const + { + return m_pData->m_bActive; + } + + void ControllerFrame::frameAction( FrameAction _eAction ) + { + bool bActive = m_pData->m_bActive; + + switch ( _eAction ) + { + case FrameAction_FRAME_ACTIVATED: + case FrameAction_FRAME_UI_ACTIVATED: + bActive = true; + break; + + case FrameAction_FRAME_DEACTIVATING: + case FrameAction_FRAME_UI_DEACTIVATING: + bActive = false; + break; + + default: + break; + } + + lcl_updateActive_nothrow( *m_pData, bActive ); + } + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/misc/databaseobjectview.cxx b/dbaccess/source/ui/misc/databaseobjectview.cxx new file mode 100644 index 000000000..cb4478295 --- /dev/null +++ b/dbaccess/source/ui/misc/databaseobjectview.cxx @@ -0,0 +1,280 @@ +/* -*- 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 <databaseobjectview.hxx> +#include <strings.hxx> +#include <asyncmodaldialog.hxx> + +#include <com/sun/star/lang/XSingleServiceFactory.hpp> +#include <com/sun/star/frame/TaskCreator.hpp> +#include <com/sun/star/frame/XFrame.hpp> +#include <com/sun/star/sdb/CommandType.hpp> +#include <com/sun/star/sdb/application/XTableUIProvider.hpp> +#include <com/sun/star/beans/NamedValue.hpp> + +#include <connectivity/dbtools.hxx> +#include <osl/diagnose.h> +#include <toolkit/helper/vclunohelper.hxx> +#include <tools/diagnose_ex.h> +#include <vcl/window.hxx> + +namespace dbaui +{ + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::sdbc; + using namespace ::com::sun::star::sdb; + using namespace ::com::sun::star::sdb::application; + using namespace ::com::sun::star::ui::dialogs; + using namespace ::com::sun::star::frame; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::awt; + + // DatabaseObjectView + DatabaseObjectView::DatabaseObjectView( const Reference< XComponentContext >& _rxORB, + const Reference< XDatabaseDocumentUI >& _rxApplication, + const Reference< XFrame >& _rxParentFrame, + const OUString& _rComponentURL ) + :m_xORB ( _rxORB ) + ,m_xParentFrame ( _rxParentFrame ) + ,m_xApplication ( _rxApplication ) + ,m_sComponentURL ( _rComponentURL ) + { + OSL_ENSURE( m_xORB.is(), "DatabaseObjectView::DatabaseObjectView: invalid service factory!" ); + OSL_ENSURE( m_xApplication.is(), "DatabaseObjectView::DatabaseObjectView: invalid connection!" ); + } + + Reference< XConnection > DatabaseObjectView::getConnection() const + { + Reference< XConnection > xConnection; + if ( m_xApplication.is() ) + xConnection = m_xApplication->getActiveConnection(); + return xConnection; + } + + Reference< XComponent > DatabaseObjectView::createNew( const Reference< XDataSource >& _xDataSource, const ::comphelper::NamedValueCollection& i_rDispatchArgs ) + { + return doCreateView( Any( _xDataSource ), OUString(), i_rDispatchArgs ); + } + + Reference< XComponent > DatabaseObjectView::openExisting( const Any& _rDataSource, const OUString& _rName, + const ::comphelper::NamedValueCollection& i_rDispatchArgs ) + { + return doCreateView( _rDataSource, _rName, i_rDispatchArgs ); + } + + Reference< XComponent > DatabaseObjectView::doCreateView( const Any& _rDataSource, const OUString& _rObjectName, + const ::comphelper::NamedValueCollection& i_rCreationArgs ) + { + ::comphelper::NamedValueCollection aDispatchArgs; + + aDispatchArgs.merge( i_rCreationArgs, false ); // false => do not overwrite + fillDispatchArgs( aDispatchArgs, _rDataSource, _rObjectName ); + aDispatchArgs.merge( i_rCreationArgs, true ); // true => do overwrite + + return doDispatch( aDispatchArgs ); + } + + Reference< XComponent > DatabaseObjectView::doDispatch( const ::comphelper::NamedValueCollection& i_rDispatchArgs ) + { + Reference< XComponent > xReturn; + if ( m_xORB.is() ) + { + try + { + // if we have no externally provided frame, create one + if ( !m_xFrameLoader.is() ) + { + Reference< XSingleServiceFactory > xFact = TaskCreator::create(m_xORB); + Sequence< Any > lArgs{ Any(NamedValue("ParentFrame", Any(m_xParentFrame))), + Any(NamedValue("TopWindow", Any(true))), + Any(NamedValue("SupportPersistentWindowState", + Any(true))) }; + + m_xFrameLoader.set(xFact->createInstanceWithArguments(lArgs), UNO_QUERY_THROW); + + // everything we load can be considered a "top level document", so set the respective bit at the window. + // This, amongst other things, triggers that the component in this task participates in the + // "ThisComponent"-game for the global application Basic. + const Reference< XFrame > xFrame( m_xFrameLoader, UNO_QUERY_THROW ); + const Reference< XWindow > xFrameWindow( xFrame->getContainerWindow(), UNO_SET_THROW ); + VclPtr<vcl::Window> pContainerWindow = VCLUnoHelper::GetWindow( xFrameWindow ); + ENSURE_OR_THROW( pContainerWindow, "no implementation access to the frame's container window!" ); + pContainerWindow->SetExtendedStyle( pContainerWindow->GetExtendedStyle() | WindowExtendedStyle::Document ); + } + + Reference< XComponentLoader > xFrameLoader( m_xFrameLoader, UNO_SET_THROW ); + xReturn = xFrameLoader->loadComponentFromURL( + m_sComponentURL, + "_self", + 0, + i_rDispatchArgs.getPropertyValues() + ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + return xReturn; + } + + void DatabaseObjectView::fillDispatchArgs( + ::comphelper::NamedValueCollection& i_rDispatchArgs, + const Any& _aDataSource, + const OUString& /* _rName */ + ) + { + OUString sDataSource; + Reference<XDataSource> xDataSource; + if ( _aDataSource >>= sDataSource ) + { + i_rDispatchArgs.put( PROPERTY_DATASOURCENAME, sDataSource ); + } + else if ( _aDataSource >>= xDataSource ) + { + i_rDispatchArgs.put( PROPERTY_DATASOURCE, xDataSource ); + } + + i_rDispatchArgs.put( PROPERTY_ACTIVE_CONNECTION, getConnection() ); + } + + // QueryDesigner + QueryDesigner::QueryDesigner( const Reference< XComponentContext >& _rxORB, const Reference< XDatabaseDocumentUI >& _rxApplication, + const Reference< XFrame >& _rxParentFrame, bool _bCreateView ) + :DatabaseObjectView( _rxORB, _rxApplication, _rxParentFrame, _bCreateView ? OUString(URL_COMPONENT_VIEWDESIGN) : OUString(URL_COMPONENT_QUERYDESIGN) ) + ,m_nCommandType( _bCreateView ? CommandType::TABLE : CommandType::QUERY ) + { + } + + void QueryDesigner::fillDispatchArgs( ::comphelper::NamedValueCollection& i_rDispatchArgs, const Any& _aDataSource, + const OUString& _rObjectName ) + { + DatabaseObjectView::fillDispatchArgs( i_rDispatchArgs, _aDataSource, _rObjectName ); + + const bool bIncludeQueryName = !_rObjectName.isEmpty(); + const bool bGraphicalDesign = i_rDispatchArgs.getOrDefault( PROPERTY_GRAPHICAL_DESIGN, true ); + const bool bEditViewAsSQLCommand = ( m_nCommandType == CommandType::TABLE ) && !bGraphicalDesign; + + i_rDispatchArgs.put( PROPERTY_COMMAND_TYPE, m_nCommandType ); + + if ( bIncludeQueryName ) + { + i_rDispatchArgs.put( PROPERTY_COMMAND, _rObjectName ); + } + + if ( bEditViewAsSQLCommand ) + { + i_rDispatchArgs.put( PROPERTY_ESCAPE_PROCESSING, false ); + } + } + + // TableDesigner + TableDesigner::TableDesigner( const Reference< XComponentContext >& _rxORB, const Reference< XDatabaseDocumentUI >& _rxApplication, const Reference< XFrame >& _rxParentFrame ) + :DatabaseObjectView( _rxORB, _rxApplication, _rxParentFrame, static_cast< OUString >( URL_COMPONENT_TABLEDESIGN ) ) + { + } + + void TableDesigner::fillDispatchArgs( ::comphelper::NamedValueCollection& i_rDispatchArgs, const Any& _aDataSource, + const OUString& _rObjectName ) + { + DatabaseObjectView::fillDispatchArgs( i_rDispatchArgs, _aDataSource, _rObjectName ); + + if ( !_rObjectName.isEmpty() ) + { + i_rDispatchArgs.put( PROPERTY_CURRENTTABLE, _rObjectName ); + } + } + + Reference< XComponent > TableDesigner::doCreateView( const Any& _rDataSource, const OUString& _rObjectName, + const ::comphelper::NamedValueCollection& i_rCreationArgs ) + { + bool bIsNewDesign = _rObjectName.isEmpty(); + + // let's see whether the connection can provide a dedicated table designer + Reference< XInterface > xDesigner; + if ( !bIsNewDesign ) + xDesigner = impl_getConnectionProvidedDesigner_nothrow( _rObjectName ); + + if ( !xDesigner.is() ) + return DatabaseObjectView::doCreateView( _rDataSource, _rObjectName, i_rCreationArgs ); + + // try whether the designer is a dialog + Reference< XExecutableDialog > xDialog( xDesigner, UNO_QUERY_THROW ); + try { AsyncDialogExecutor::executeModalDialogAsync( xDialog ); } + catch( const Exception& ) { DBG_UNHANDLED_EXCEPTION("dbaccess"); } + return nullptr; + } + + Reference< XInterface > TableDesigner::impl_getConnectionProvidedDesigner_nothrow( const OUString& _rTableName ) + { + Reference< XInterface > xDesigner; + try + { + Reference< XTableUIProvider > xTableUIProv( getConnection(), UNO_QUERY ); + if ( xTableUIProv.is() ) + xDesigner = xTableUIProv->getTableEditor( getApplicationUI(), _rTableName ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + return xDesigner; + } + + // ResultSetBrowser + ResultSetBrowser::ResultSetBrowser( const Reference< XComponentContext >& _rxORB, const Reference< XDatabaseDocumentUI >& _rxApplication, const Reference< XFrame >& _rxParentFrame, + bool _bTable ) + :DatabaseObjectView( _rxORB, _rxApplication, _rxParentFrame, static_cast < OUString >( URL_COMPONENT_DATASOURCEBROWSER ) ) + ,m_bTable(_bTable) + { + } + + void ResultSetBrowser::fillDispatchArgs( ::comphelper::NamedValueCollection& i_rDispatchArgs, const Any& _aDataSource, + const OUString& _rQualifiedName) + { + DatabaseObjectView::fillDispatchArgs( i_rDispatchArgs, _aDataSource, _rQualifiedName ); + OSL_ENSURE( !_rQualifiedName.isEmpty(),"A Table name must be set"); + OUString sCatalog; + OUString sSchema; + OUString sTable; + if ( m_bTable ) + ::dbtools::qualifiedNameComponents( getConnection()->getMetaData(), _rQualifiedName, sCatalog, sSchema, sTable, ::dbtools::EComposeRule::InDataManipulation ); + + i_rDispatchArgs.put( PROPERTY_COMMAND_TYPE, (m_bTable ? CommandType::TABLE : CommandType::QUERY) ); + i_rDispatchArgs.put( PROPERTY_COMMAND, _rQualifiedName ); + i_rDispatchArgs.put( PROPERTY_ENABLE_BROWSER, false ); + + if ( m_bTable ) + { + i_rDispatchArgs.put( PROPERTY_UPDATE_CATALOGNAME, sCatalog ); + i_rDispatchArgs.put( PROPERTY_UPDATE_SCHEMANAME, sSchema ); + i_rDispatchArgs.put( PROPERTY_UPDATE_TABLENAME, sTable ); + } + } + + // RelationDesigner + RelationDesigner::RelationDesigner( const Reference< XComponentContext >& _rxORB, const Reference< XDatabaseDocumentUI >& _rxApplication, const Reference< XFrame >& _rxParentFrame ) + :DatabaseObjectView( _rxORB, _rxApplication, _rxParentFrame, static_cast< OUString >( URL_COMPONENT_RELATIONDESIGN ) ) + { + } +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/misc/datasourceconnector.cxx b/dbaccess/source/ui/misc/datasourceconnector.cxx new file mode 100644 index 000000000..49053e569 --- /dev/null +++ b/dbaccess/source/ui/misc/datasourceconnector.cxx @@ -0,0 +1,202 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <core_resource.hxx> +#include <datasourceconnector.hxx> +#include <osl/diagnose.h> +#include <com/sun/star/sdbc/XWarningsSupplier.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/sdb/XCompletedConnection.hpp> +#include <com/sun/star/task/InteractionHandler.hpp> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/sdbc/SQLWarning.hpp> +#include <comphelper/namedvaluecollection.hxx> +#include <connectivity/dbexception.hxx> +#include <com/sun/star/sdbc/XDataSource.hpp> +#include <UITools.hxx> +#include <vcl/outdev.hxx> +#include <vcl/stdtext.hxx> +#include <vcl/weld.hxx> +#include <tools/diagnose_ex.h> +#include <cppuhelper/exc_hlp.hxx> +#include <strings.hrc> +#include <strings.hxx> + +namespace dbaui +{ + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::sdb; + using namespace ::com::sun::star::sdbc; + using namespace ::com::sun::star::task; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::container; + using namespace ::com::sun::star::frame; + using namespace ::dbtools; + + // ODatasourceConnector + ODatasourceConnector::ODatasourceConnector(const Reference< XComponentContext >& _rxContext, weld::Window* _pMessageParent) + :m_pErrorMessageParent(_pMessageParent) + ,m_xContext(_rxContext) + { + } + + ODatasourceConnector::ODatasourceConnector( const Reference< XComponentContext >& _rxContext, weld::Window* _pMessageParent, + const OUString& _rContextInformation ) + :m_pErrorMessageParent(_pMessageParent) + ,m_xContext(_rxContext) + ,m_sContextInformation( _rContextInformation ) + { + } + + Reference< XConnection > ODatasourceConnector::connect( const OUString& _rDataSourceName, + ::dbtools::SQLExceptionInfo* _pErrorInfo ) const + { + Reference< XConnection > xConnection; + + OSL_ENSURE(isValid(), "ODatasourceConnector::connect: invalid object!"); + if (!isValid()) + return xConnection; + + // get the data source + Reference< XDataSource > xDatasource = + getDataSourceByName( _rDataSourceName, m_pErrorMessageParent, m_xContext, _pErrorInfo ); + + if ( xDatasource.is() ) + xConnection = connect( xDatasource, _pErrorInfo ); + return xConnection; + } + + Reference< XConnection > ODatasourceConnector::connect(const Reference< XDataSource>& _xDataSource, + ::dbtools::SQLExceptionInfo* _pErrorInfo ) const + { + Reference< XConnection > xConnection; + + OSL_ENSURE( isValid() && _xDataSource.is(), "ODatasourceConnector::connect: invalid object or argument!" ); + if ( !isValid() || !_xDataSource.is() ) + return xConnection; + + // get user/password + OUString sPassword, sUser; + bool bPwdRequired = false; + Reference<XPropertySet> xProp(_xDataSource,UNO_QUERY); + try + { + xProp->getPropertyValue(PROPERTY_PASSWORD) >>= sPassword; + xProp->getPropertyValue(PROPERTY_ISPASSWORDREQUIRED) >>= bPwdRequired; + xProp->getPropertyValue(PROPERTY_USER) >>= sUser; + } + catch(Exception&) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + // try to connect + SQLExceptionInfo aInfo; + try + { + if (bPwdRequired && sPassword.isEmpty()) + { // password required, but empty -> connect using an interaction handler + Reference< XCompletedConnection > xConnectionCompletion( _xDataSource, UNO_QUERY_THROW ); + + Reference< XModel > xModel( getDataSourceOrModel( _xDataSource ), UNO_QUERY_THROW ); + ::comphelper::NamedValueCollection aArgs( xModel->getArgs() ); + Reference< XInteractionHandler > xHandler( aArgs.getOrDefault( "InteractionHandler", Reference< XInteractionHandler >() ) ); + + if ( !xHandler.is() ) + { + // instantiate the default SDB interaction handler + xHandler = InteractionHandler::createWithParent(m_xContext, m_pErrorMessageParent ? m_pErrorMessageParent->GetXWindow() : nullptr); + } + + xConnection = xConnectionCompletion->connectWithCompletion(xHandler); + } + else + { + xConnection = _xDataSource->getConnection(sUser, sPassword); + } + } + catch( const SQLException& ) + { + aInfo = ::cppu::getCaughtException(); + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + if ( !aInfo.isValid() ) + { + // there was no error during connecting, but perhaps a warning? + Reference< XWarningsSupplier > xConnectionWarnings( xConnection, UNO_QUERY ); + if ( xConnectionWarnings.is() ) + { + try + { + Any aWarnings( xConnectionWarnings->getWarnings() ); + if ( aWarnings.hasValue() ) + { + OUString sMessage( DBA_RES( STR_WARNINGS_DURING_CONNECT ) ); + sMessage = sMessage.replaceFirst( "$buttontext$", GetStandardText( StandardButtonType::More ) ); + sMessage = OutputDevice::GetNonMnemonicString( sMessage ); + + SQLWarning aContext; + aContext.Message = sMessage; + aContext.NextException = aWarnings; + aInfo = aContext; + } + xConnectionWarnings->clearWarnings(); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + } + else + { + if ( !m_sContextInformation.isEmpty() ) + { + SQLException aError; + aError.Message = m_sContextInformation; + aError.NextException = aInfo.get(); + + aInfo = aError; + } + } + + // was there an error? + if ( aInfo.isValid() ) + { + if ( _pErrorInfo ) + { + *_pErrorInfo = aInfo; + } + else + { + showError(aInfo, m_pErrorMessageParent ? m_pErrorMessageParent->GetXWindow() : nullptr, m_xContext); + } + } + return xConnection; + } + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/misc/dbaundomanager.cxx b/dbaccess/source/ui/misc/dbaundomanager.cxx new file mode 100644 index 000000000..9ed72bbdf --- /dev/null +++ b/dbaccess/source/ui/misc/dbaundomanager.cxx @@ -0,0 +1,324 @@ +/* -*- 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 <dbaccess/dbaundomanager.hxx> + +#include <com/sun/star/lang/DisposedException.hpp> +#include <com/sun/star/lang/NoSupportException.hpp> + +#include <svl/undo.hxx> +#include <vcl/svapp.hxx> +#include <framework/undomanagerhelper.hxx> +#include <framework/imutex.hxx> + +namespace dbaui +{ + + using ::com::sun::star::uno::Reference; + using ::com::sun::star::uno::XInterface; + using ::com::sun::star::uno::Sequence; + using ::com::sun::star::document::XUndoManager; + using ::com::sun::star::lang::DisposedException; + using ::com::sun::star::document::XUndoAction; + using ::com::sun::star::document::XUndoManagerListener; + using ::com::sun::star::lang::NoSupportException; + + // UndoManager_Impl + struct UndoManager_Impl : public ::framework::IUndoManagerImplementation + { + UndoManager_Impl( UndoManager& i_antiImpl, ::cppu::OWeakObject& i_parent, ::osl::Mutex& i_mutex ) + :rAntiImpl( i_antiImpl ) + ,rParent( i_parent ) + ,rMutex( i_mutex ) + ,bDisposed( false ) + ,aUndoHelper( *this ) + { + } + + virtual ~UndoManager_Impl() + { + } + + UndoManager& rAntiImpl; + ::cppu::OWeakObject& rParent; + ::osl::Mutex& rMutex; + bool bDisposed; + SfxUndoManager aUndoManager; + ::framework::UndoManagerHelper aUndoHelper; + + // IUndoManagerImplementation + virtual SfxUndoManager& getImplUndoManager() override; + virtual Reference< XUndoManager > getThis() override; + }; + + SfxUndoManager& UndoManager_Impl::getImplUndoManager() + { + return aUndoManager; + } + + Reference< XUndoManager > UndoManager_Impl::getThis() + { + return static_cast< XUndoManager* >( &rAntiImpl ); + } + + namespace { + + // OslMutexFacade + class OslMutexFacade : public ::framework::IMutex + { + public: + explicit OslMutexFacade( ::osl::Mutex& i_mutex ) + :m_rMutex( i_mutex ) + { + } + + virtual ~OslMutexFacade() {} + + virtual void acquire() override; + virtual void release() override; + + private: + ::osl::Mutex& m_rMutex; + }; + + } + + void OslMutexFacade::acquire() + { + m_rMutex.acquire(); + } + + void OslMutexFacade::release() + { + m_rMutex.release(); + } + + namespace { + + // UndoManagerMethodGuard + /** guard for public UNO methods of the UndoManager + */ + class UndoManagerMethodGuard : public ::framework::IMutexGuard + { + public: + explicit UndoManagerMethodGuard( UndoManager_Impl& i_impl ) + :m_aGuard( i_impl.rMutex ) + ,m_aMutexFacade( i_impl.rMutex ) + { + // throw if the instance is already disposed + if ( i_impl.bDisposed ) + throw DisposedException( OUString(), i_impl.getThis() ); + } + virtual ~UndoManagerMethodGuard() + { + } + + // IMutexGuard + virtual void clear() override; + virtual ::framework::IMutex& getGuardedMutex() override; + + private: + osl::ClearableMutexGuard m_aGuard; + OslMutexFacade m_aMutexFacade; + }; + + } + + ::framework::IMutex& UndoManagerMethodGuard::getGuardedMutex() + { + return m_aMutexFacade; + } + + void UndoManagerMethodGuard::clear() + { + m_aGuard.clear(); + } + + // UndoManager + UndoManager::UndoManager( ::cppu::OWeakObject& i_parent, ::osl::Mutex& i_mutex ) + :m_xImpl( new UndoManager_Impl( *this, i_parent, i_mutex ) ) + { + } + + UndoManager::~UndoManager() + { + } + + SfxUndoManager& UndoManager::GetSfxUndoManager() const + { + return m_xImpl->aUndoManager; + } + + void SAL_CALL UndoManager::acquire( ) noexcept + { + m_xImpl->rParent.acquire(); + } + + void SAL_CALL UndoManager::release( ) noexcept + { + m_xImpl->rParent.release(); + } + + void UndoManager::disposing() + { + { + ::osl::MutexGuard aGuard( m_xImpl->rMutex ); + m_xImpl->bDisposed = true; + } + m_xImpl->aUndoHelper.disposing(); + } + + void SAL_CALL UndoManager::enterUndoContext( const OUString& i_title ) + { + UndoManagerMethodGuard aGuard( *m_xImpl ); + m_xImpl->aUndoHelper.enterUndoContext( i_title, aGuard ); + } + + void SAL_CALL UndoManager::enterHiddenUndoContext( ) + { + UndoManagerMethodGuard aGuard( *m_xImpl ); + m_xImpl->aUndoHelper.enterHiddenUndoContext( aGuard ); + } + + void SAL_CALL UndoManager::leaveUndoContext( ) + { + UndoManagerMethodGuard aGuard( *m_xImpl ); + m_xImpl->aUndoHelper.leaveUndoContext( aGuard ); + } + + void SAL_CALL UndoManager::addUndoAction( const Reference< XUndoAction >& i_action ) + { + UndoManagerMethodGuard aGuard( *m_xImpl ); + m_xImpl->aUndoHelper.addUndoAction( i_action, aGuard ); + } + + void SAL_CALL UndoManager::undo( ) + { + SolarMutexGuard aSolarGuard; + // (all our UndoActions work directly on VCL code, usually, so ...) + UndoManagerMethodGuard aGuard( *m_xImpl ); + m_xImpl->aUndoHelper.undo( aGuard ); + } + + void SAL_CALL UndoManager::redo( ) + { + SolarMutexGuard aSolarGuard; + // (all our UndoActions work directly on VCL code, usually, so ...) + UndoManagerMethodGuard aGuard( *m_xImpl ); + m_xImpl->aUndoHelper.redo( aGuard ); + } + + sal_Bool SAL_CALL UndoManager::isUndoPossible( ) + { + UndoManagerMethodGuard aGuard( *m_xImpl ); + return m_xImpl->aUndoHelper.isUndoPossible(); + } + + sal_Bool SAL_CALL UndoManager::isRedoPossible( ) + { + UndoManagerMethodGuard aGuard( *m_xImpl ); + return m_xImpl->aUndoHelper.isRedoPossible(); + } + + OUString SAL_CALL UndoManager::getCurrentUndoActionTitle( ) + { + UndoManagerMethodGuard aGuard( *m_xImpl ); + return m_xImpl->aUndoHelper.getCurrentUndoActionTitle(); + } + + OUString SAL_CALL UndoManager::getCurrentRedoActionTitle( ) + { + UndoManagerMethodGuard aGuard( *m_xImpl ); + return m_xImpl->aUndoHelper.getCurrentRedoActionTitle(); + } + + Sequence< OUString > SAL_CALL UndoManager::getAllUndoActionTitles( ) + { + UndoManagerMethodGuard aGuard( *m_xImpl ); + return m_xImpl->aUndoHelper.getAllUndoActionTitles(); + } + + Sequence< OUString > SAL_CALL UndoManager::getAllRedoActionTitles( ) + { + UndoManagerMethodGuard aGuard( *m_xImpl ); + return m_xImpl->aUndoHelper.getAllRedoActionTitles(); + } + + void SAL_CALL UndoManager::clear( ) + { + UndoManagerMethodGuard aGuard( *m_xImpl ); + m_xImpl->aUndoHelper.clear( aGuard ); + } + + void SAL_CALL UndoManager::clearRedo( ) + { + UndoManagerMethodGuard aGuard( *m_xImpl ); + m_xImpl->aUndoHelper.clearRedo( aGuard ); + } + + void SAL_CALL UndoManager::reset( ) + { + UndoManagerMethodGuard aGuard( *m_xImpl ); + m_xImpl->aUndoHelper.reset( aGuard ); + } + + void SAL_CALL UndoManager::addUndoManagerListener( const Reference< XUndoManagerListener >& i_listener ) + { + UndoManagerMethodGuard aGuard( *m_xImpl ); + m_xImpl->aUndoHelper.addUndoManagerListener( i_listener ); + } + + void SAL_CALL UndoManager::removeUndoManagerListener( const Reference< XUndoManagerListener >& i_listener ) + { + UndoManagerMethodGuard aGuard( *m_xImpl ); + m_xImpl->aUndoHelper.removeUndoManagerListener( i_listener ); + } + + void SAL_CALL UndoManager::lock( ) + { + UndoManagerMethodGuard aGuard( *m_xImpl ); + m_xImpl->aUndoHelper.lock(); + } + + void SAL_CALL UndoManager::unlock( ) + { + UndoManagerMethodGuard aGuard( *m_xImpl ); + m_xImpl->aUndoHelper.unlock(); + } + + sal_Bool SAL_CALL UndoManager::isLocked( ) + { + UndoManagerMethodGuard aGuard( *m_xImpl ); + return m_xImpl->aUndoHelper.isLocked(); + } + + Reference< XInterface > SAL_CALL UndoManager::getParent( ) + { + UndoManagerMethodGuard aGuard( *m_xImpl ); + return m_xImpl->rParent; + } + + void SAL_CALL UndoManager::setParent( const Reference< XInterface >& ) + { + throw NoSupportException( OUString(), m_xImpl->getThis() ); + } + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/misc/dbsubcomponentcontroller.cxx b/dbaccess/source/ui/misc/dbsubcomponentcontroller.cxx new file mode 100644 index 000000000..467a6e925 --- /dev/null +++ b/dbaccess/source/ui/misc/dbsubcomponentcontroller.cxx @@ -0,0 +1,606 @@ +/* -*- 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 <browserids.hxx> +#include <commontypes.hxx> +#include <core_resource.hxx> +#include <dbaccess/dataview.hxx> +#include <strings.hrc> +#include <strings.hxx> +#include <dbaccess/dbsubcomponentcontroller.hxx> + +#include <com/sun/star/frame/XUntitledNumbers.hpp> +#include <com/sun/star/container/XChild.hpp> +#include <com/sun/star/sdb/XDocumentDataSource.hpp> +#include <com/sun/star/sdb/XOfficeDatabaseDocument.hpp> +#include <com/sun/star/sdbc/XDataSource.hpp> +#include <com/sun/star/util/NumberFormatter.hpp> +#include <com/sun/star/lang/IllegalArgumentException.hpp> + +#include <comphelper/types.hxx> +#include <connectivity/dbexception.hxx> +#include <connectivity/dbmetadata.hxx> +#include <connectivity/dbtools.hxx> +#include <comphelper/interfacecontainer3.hxx> +#include <rtl/ustrbuf.hxx> +#include <sal/log.hxx> +#include <toolkit/helper/vclunohelper.hxx> +#include <tools/debug.hxx> +#include <tools/diagnose_ex.h> +#include <vcl/svapp.hxx> +#include <vcl/weld.hxx> + +namespace dbaui +{ + + using ::com::sun::star::uno::Any; + using ::com::sun::star::uno::Reference; + using ::com::sun::star::beans::XPropertySet; + using ::com::sun::star::uno::Sequence; + using ::com::sun::star::uno::Type; + using ::com::sun::star::uno::XComponentContext; + using ::com::sun::star::sdbc::XConnection; + using ::com::sun::star::uno::UNO_QUERY; + using ::com::sun::star::container::XChild; + using ::com::sun::star::sdbc::XDataSource; + using ::com::sun::star::util::NumberFormatter; + using ::com::sun::star::util::XNumberFormatter; + using ::com::sun::star::util::XNumberFormatsSupplier; + using ::com::sun::star::frame::XFrame; + using ::com::sun::star::uno::Exception; + using ::com::sun::star::lang::EventObject; + using ::com::sun::star::beans::PropertyValue; + using ::com::sun::star::frame::XModel; + using ::com::sun::star::sdb::XOfficeDatabaseDocument; + using ::com::sun::star::awt::XWindow; + using ::com::sun::star::sdbc::XDatabaseMetaData; + using ::com::sun::star::sdb::XDocumentDataSource; + using ::com::sun::star::document::XEmbeddedScripts; + using ::com::sun::star::lang::IllegalArgumentException; + using ::com::sun::star::uno::UNO_SET_THROW; + using ::com::sun::star::uno::UNO_QUERY_THROW; + using ::com::sun::star::frame::XUntitledNumbers; + + namespace { + + class DataSourceHolder + { + public: + DataSourceHolder() + { + } + + explicit DataSourceHolder(const Reference< XDataSource >& _rxDataSource) + : m_xDataSource(_rxDataSource) + { + Reference< XDocumentDataSource > xDocDS( m_xDataSource, UNO_QUERY ); + if ( xDocDS.is() ) + m_xDocument = xDocDS->getDatabaseDocument(); + + m_xDataSourceProps.set( m_xDataSource, UNO_QUERY ); + } + + const Reference< XDataSource >& getDataSource() const { return m_xDataSource; } + const Reference< XPropertySet >& getDataSourceProps() const { return m_xDataSourceProps; } + const Reference< XOfficeDatabaseDocument >& getDatabaseDocument() const { return m_xDocument; } + + bool is() const { return m_xDataSource.is(); } + + void clear() + { + m_xDataSource.clear(); + m_xDocument.clear(); + } + + private: + Reference< XDataSource > m_xDataSource; + Reference< XPropertySet > m_xDataSourceProps; + Reference< XOfficeDatabaseDocument > m_xDocument; + }; + + } + + struct DBSubComponentController_Impl + { + private: + ::std::optional< bool > m_aDocScriptSupport; + + public: + ::dbtools::SQLExceptionInfo m_aCurrentError; + + ::comphelper::OInterfaceContainerHelper3<css::util::XModifyListener> + m_aModifyListeners; + + // <properties> + SharedConnection m_xConnection; + ::dbtools::DatabaseMetaData m_aSdbMetaData; + // </properties> + OUString m_sDataSourceName; // the data source we're working for + DataSourceHolder m_aDataSource; + Reference< XNumberFormatter > m_xFormatter; // a number formatter working with the connection's NumberFormatsSupplier + sal_Int32 m_nDocStartNumber; + bool m_bSuspended; // is true when the controller was already suspended + bool m_bEditable; // is the control readonly or not + bool m_bModified; // is the data modified + bool m_bNotAttached; + + explicit DBSubComponentController_Impl(osl::Mutex& i_rMutex) + :m_aModifyListeners( i_rMutex ) + ,m_nDocStartNumber(0) + ,m_bSuspended( false ) + ,m_bEditable(true) + ,m_bModified(false) + ,m_bNotAttached(true) + { + } + + bool documentHasScriptSupport() const + { + OSL_PRECOND( !!m_aDocScriptSupport, + "DBSubComponentController_Impl::documentHasScriptSupport: not completely initialized, yet - don't know!?" ); + return !!m_aDocScriptSupport && *m_aDocScriptSupport; + } + + void setDocumentScriptSupport( const bool _bSupport ) + { + OSL_PRECOND( !m_aDocScriptSupport, + "DBSubComponentController_Impl::setDocumentScriptSupport: already initialized!" ); + m_aDocScriptSupport = ::std::optional< bool >( _bSupport ); + } + }; + + // DBSubComponentController + DBSubComponentController::DBSubComponentController(const Reference< XComponentContext >& _rxORB) + :DBSubComponentController_Base( _rxORB ) + ,m_pImpl( new DBSubComponentController_Impl( getMutex() ) ) + { + } + + DBSubComponentController::~DBSubComponentController() + { + } + + void DBSubComponentController::impl_initialize() + { + OGenericUnoController::impl_initialize(); + + const ::comphelper::NamedValueCollection& rArguments( getInitParams() ); + + Reference< XConnection > xConnection; + xConnection = rArguments.getOrDefault( PROPERTY_ACTIVE_CONNECTION, xConnection ); + + if ( !xConnection.is() ) + ::dbtools::isEmbeddedInDatabase( getModel(), xConnection ); + + if ( xConnection.is() ) + initializeConnection( xConnection ); + + bool bShowError = true; + if ( !isConnected() ) + { + reconnect( false ); + bShowError = false; + } + if ( !isConnected() ) + { + if ( bShowError ) + connectionLostMessage(); + throw IllegalArgumentException(); + } + } + + Any SAL_CALL DBSubComponentController::queryInterface(const Type& _rType) + { + if ( _rType.equals( cppu::UnoType<XScriptInvocationContext>::get() ) ) + { + if ( m_pImpl->documentHasScriptSupport() ) + return Any( Reference< XScriptInvocationContext >( this ) ); + return Any(); + } + + return DBSubComponentController_Base::queryInterface( _rType ); + } + + Sequence< Type > SAL_CALL DBSubComponentController::getTypes( ) + { + Sequence< Type > aTypes( DBSubComponentController_Base::getTypes() ); + if ( !m_pImpl->documentHasScriptSupport() ) + { + auto [begin, end] = asNonConstRange(aTypes); + auto newEnd = std::remove_if( begin, end, + [](const Type& type) + { return type == cppu::UnoType<XScriptInvocationContext>::get(); } ); + aTypes.realloc( std::distance(begin, newEnd) ); + } + return aTypes; + } + + void DBSubComponentController::initializeConnection( const Reference< XConnection >& _rxForeignConn ) + { + DBG_ASSERT( !isConnected(), "DBSubComponentController::initializeConnection: not to be called when already connected!" ); + // usually this gets called from within initialize of derived classes ... + if ( isConnected() ) + disconnect(); + + m_pImpl->m_xConnection.reset( _rxForeignConn, SharedConnection::NoTakeOwnership ); + m_pImpl->m_aSdbMetaData.reset( m_pImpl->m_xConnection ); + startConnectionListening( m_pImpl->m_xConnection ); + + // get the data source the connection belongs to + try + { + // determine our data source + OSL_PRECOND( !m_pImpl->m_aDataSource.is(), "DBSubComponentController::initializeConnection: already a data source in this phase?" ); + { + Reference< XChild > xConnAsChild( m_pImpl->m_xConnection, UNO_QUERY ); + Reference< XDataSource > xDS; + if ( xConnAsChild.is() ) + xDS.set( xConnAsChild->getParent(), UNO_QUERY ); + + // (take the indirection through XDataSource to ensure we have a correct object...) + m_pImpl->m_aDataSource = DataSourceHolder(xDS); + } + SAL_WARN_IF( !m_pImpl->m_aDataSource.is(), "dbaccess.ui", "DBSubComponentController::initializeConnection: unable to obtain the data source object!" ); + + if ( m_pImpl->m_bNotAttached ) + { + Reference< XUntitledNumbers > xUntitledProvider( getDatabaseDocument(), UNO_QUERY ); + m_pImpl->m_nDocStartNumber = 1; + if ( xUntitledProvider.is() ) + m_pImpl->m_nDocStartNumber = xUntitledProvider->leaseNumber( static_cast< XWeak* >( this ) ); + } + + // determine the availability of script support in our document. Our own XScriptInvocationContext + // interface depends on this + m_pImpl->setDocumentScriptSupport( Reference< XEmbeddedScripts >( getDatabaseDocument(), UNO_QUERY ).is() ); + + // get a number formatter + Reference< XPropertySet > xDataSourceProps( m_pImpl->m_aDataSource.getDataSourceProps(), UNO_SET_THROW ); + xDataSourceProps->getPropertyValue( PROPERTY_NAME ) >>= m_pImpl->m_sDataSourceName; + DBG_ASSERT( !m_pImpl->m_sDataSourceName.isEmpty(), "DBSubComponentController::initializeConnection: invalid data source name!" ); + Reference< XNumberFormatsSupplier> xSupplier = ::dbtools::getNumberFormats(m_pImpl->m_xConnection); + if(xSupplier.is()) + { + m_pImpl->m_xFormatter.set(NumberFormatter::create(getORB()), UNO_QUERY_THROW); + m_pImpl->m_xFormatter->attachNumberFormatsSupplier(xSupplier); + } + OSL_ENSURE(m_pImpl->m_xFormatter.is(),"No NumberFormatter!"); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + + void DBSubComponentController::reconnect( bool _bUI ) + { + OSL_ENSURE(!m_pImpl->m_bSuspended, "Cannot reconnect while suspended!"); + + stopConnectionListening( m_pImpl->m_xConnection ); + m_pImpl->m_aSdbMetaData.reset( nullptr ); + m_pImpl->m_xConnection.clear(); + + // reconnect + bool bReConnect = true; + if ( _bUI ) + { + std::unique_ptr<weld::MessageDialog> xQuery(Application::CreateMessageDialog(getFrameWeld(), + VclMessageType::Question, VclButtonsType::YesNo, + DBA_RES(STR_QUERY_CONNECTION_LOST))); + bReConnect = (RET_YES == xQuery->run()); + } + + // now really reconnect ... + if ( bReConnect ) + { + m_pImpl->m_xConnection.reset( connect( m_pImpl->m_aDataSource.getDataSource() ), SharedConnection::TakeOwnership ); + m_pImpl->m_aSdbMetaData.reset( m_pImpl->m_xConnection ); + } + + // invalidate all slots + InvalidateAll(); + } + + void DBSubComponentController::disconnect() + { + stopConnectionListening(m_pImpl->m_xConnection); + m_pImpl->m_aSdbMetaData.reset( nullptr ); + m_pImpl->m_xConnection.clear(); + + InvalidateAll(); + } + + void DBSubComponentController::losingConnection() + { + // our connection was disposed so we need a new one + reconnect( true ); + InvalidateAll(); + } + + void SAL_CALL DBSubComponentController::disposing() + { + DBSubComponentController_Base::disposing(); + + disconnect(); + + attachFrame( Reference < XFrame >() ); + + m_pImpl->m_aDataSource.clear(); + } + + void SAL_CALL DBSubComponentController::disposing(const EventObject& _rSource) + { + if ( _rSource.Source == getConnection() ) + { + if ( !m_pImpl->m_bSuspended // when already suspended then we don't have to reconnect + && !getBroadcastHelper().bInDispose + && !getBroadcastHelper().bDisposed + && isConnected() + ) + { + losingConnection(); + } + else + { + m_pImpl->m_xConnection.reset( m_pImpl->m_xConnection, SharedConnection::NoTakeOwnership ); + // this prevents the "disposeComponent" call in disconnect + disconnect(); + } + } + else + DBSubComponentController_Base::disposing( _rSource ); + } + + void DBSubComponentController::appendError( const OUString& _rErrorMessage ) + { + m_pImpl->m_aCurrentError.append( ::dbtools::SQLExceptionInfo::TYPE::SQLException, _rErrorMessage, + getStandardSQLState( ::dbtools::StandardSQLState::GENERAL_ERROR ), + 1000 ); + } + void DBSubComponentController::clearError() + { + m_pImpl->m_aCurrentError = ::dbtools::SQLExceptionInfo(); + } + + bool DBSubComponentController::hasError() const + { + return m_pImpl->m_aCurrentError.isValid(); + } + + const ::dbtools::SQLExceptionInfo& DBSubComponentController::getError() const + { + return m_pImpl->m_aCurrentError; + } + + void DBSubComponentController::displayError() + { + showError( m_pImpl->m_aCurrentError ); + } + + sal_Bool SAL_CALL DBSubComponentController::suspend(sal_Bool bSuspend) + { + m_pImpl->m_bSuspended = bSuspend; + if ( !bSuspend && !isConnected() ) + reconnect(true); + + return true; + } + + sal_Bool SAL_CALL DBSubComponentController::attachModel( const Reference< XModel > & _rxModel) + { + if ( !_rxModel.is() ) + return false; + if ( !DBSubComponentController_Base::attachModel( _rxModel ) ) + return false; + + m_pImpl->m_bNotAttached = false; + if ( m_pImpl->m_nDocStartNumber == 1 ) + releaseNumberForComponent(); + + Reference< XUntitledNumbers > xUntitledProvider( _rxModel, UNO_QUERY ); + m_pImpl->m_nDocStartNumber = 1; + if ( xUntitledProvider.is() ) + m_pImpl->m_nDocStartNumber = xUntitledProvider->leaseNumber( static_cast< XWeak* >( this ) ); + + return true; + } + + void DBSubComponentController::Execute(sal_uInt16 _nId, const Sequence< PropertyValue >& _rArgs) + { + if ( _nId == ID_BROWSER_CLOSE ) + { + closeTask(); + return; + } + + DBSubComponentController_Base::Execute( _nId, _rArgs ); + InvalidateFeature( _nId ); + } + + OUString DBSubComponentController::getDataSourceName() const + { + OUString sName; + Reference< XPropertySet > xDataSourceProps( m_pImpl->m_aDataSource.getDataSourceProps() ); + if ( xDataSourceProps.is() ) + xDataSourceProps->getPropertyValue(PROPERTY_NAME) >>= sName; + return sName; + } + void DBSubComponentController::connectionLostMessage() const + { + OUString aMessage(DBA_RES(RID_STR_CONNECTION_LOST)); + Reference< XWindow > xWindow = getTopMostContainerWindow(); + vcl::Window* pWin = nullptr; + if ( xWindow.is() ) + pWin = VCLUnoHelper::GetWindow(xWindow); + if ( !pWin ) + pWin = getView()->Window::GetParent(); + + std::unique_ptr<weld::MessageDialog> xInfo(Application::CreateMessageDialog(pWin ? pWin->GetFrameWeld() : nullptr, + VclMessageType::Info, VclButtonsType::Ok, aMessage)); + xInfo->run(); + } + const Reference< XConnection >& DBSubComponentController::getConnection() const + { + return m_pImpl->m_xConnection; + } + + bool DBSubComponentController::isReadOnly() const + { + return !m_pImpl->m_bEditable; + } + + bool DBSubComponentController::isEditable() const + { + return m_pImpl->m_bEditable; + } + + void DBSubComponentController::setEditable(bool _bEditable) + { + m_pImpl->m_bEditable = _bEditable; + } + + const ::dbtools::DatabaseMetaData& DBSubComponentController::getSdbMetaData() const + { + return m_pImpl->m_aSdbMetaData; + } + + bool DBSubComponentController::isConnected() const + { + return m_pImpl->m_xConnection.is(); + } + + Reference< XDatabaseMetaData > DBSubComponentController::getMetaData( ) const + { + Reference< XDatabaseMetaData > xMeta; + try + { + if ( isConnected() ) + xMeta.set( m_pImpl->m_xConnection->getMetaData(), UNO_SET_THROW ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + return xMeta; + } + + const Reference< XPropertySet >& DBSubComponentController::getDataSource() const + { + return m_pImpl->m_aDataSource.getDataSourceProps(); + } + + bool DBSubComponentController::haveDataSource() const + { + return m_pImpl->m_aDataSource.is(); + } + + Reference< XModel > DBSubComponentController::getDatabaseDocument() const + { + return Reference< XModel >( m_pImpl->m_aDataSource.getDatabaseDocument(), UNO_QUERY ); + } + + Reference< XNumberFormatter > const & DBSubComponentController::getNumberFormatter() const + { + return m_pImpl->m_xFormatter; + } + + Reference< XModel > DBSubComponentController::getPrivateModel() const + { + return getDatabaseDocument(); + } + // XTitle + OUString SAL_CALL DBSubComponentController::getTitle() + { + ::osl::MutexGuard aGuard( getMutex() ); + if ( m_bExternalTitle ) + return impl_getTitleHelper_throw()->getTitle (); + + OUStringBuffer sTitle; + Reference< XTitle > xTitle(getPrivateModel(),UNO_QUERY); + if ( xTitle.is() ) + { + sTitle.append( xTitle->getTitle() ); + sTitle.append(" : "); + } + sTitle.append( getPrivateTitle() ); + return sTitle.makeStringAndClear(); + } + + sal_Int32 DBSubComponentController::getCurrentStartNumber() const + { + return m_pImpl->m_nDocStartNumber; + } + + Reference< XEmbeddedScripts > SAL_CALL DBSubComponentController::getScriptContainer() + { + ::osl::MutexGuard aGuard( getMutex() ); + if ( !m_pImpl->documentHasScriptSupport() ) + return nullptr; + + return Reference< XEmbeddedScripts >( getDatabaseDocument(), UNO_QUERY_THROW ); + } + + void SAL_CALL DBSubComponentController::addModifyListener( const Reference< XModifyListener >& i_Listener ) + { + ::osl::MutexGuard aGuard( getMutex() ); + m_pImpl->m_aModifyListeners.addInterface( i_Listener ); + } + + void SAL_CALL DBSubComponentController::removeModifyListener( const Reference< XModifyListener >& i_Listener ) + { + ::osl::MutexGuard aGuard( getMutex() ); + m_pImpl->m_aModifyListeners.removeInterface( i_Listener ); + } + + sal_Bool SAL_CALL DBSubComponentController::isModified( ) + { + ::osl::MutexGuard aGuard( getMutex() ); + return impl_isModified(); + } + + void SAL_CALL DBSubComponentController::setModified( sal_Bool i_bModified ) + { + ::osl::ClearableMutexGuard aGuard( getMutex() ); + + if ( m_pImpl->m_bModified == bool(i_bModified) ) + return; + + m_pImpl->m_bModified = i_bModified; + impl_onModifyChanged(); + + EventObject aEvent( *this ); + aGuard.clear(); + m_pImpl->m_aModifyListeners.notifyEach( &XModifyListener::modified, aEvent ); + } + + bool DBSubComponentController::impl_isModified() const + { + return m_pImpl->m_bModified; + } + + void DBSubComponentController::impl_onModifyChanged() + { + InvalidateFeature( ID_BROWSER_SAVEDOC ); + if ( isFeatureSupported( ID_BROWSER_SAVEASDOC ) ) + InvalidateFeature( ID_BROWSER_SAVEASDOC ); + } + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/misc/defaultobjectnamecheck.cxx b/dbaccess/source/ui/misc/defaultobjectnamecheck.cxx new file mode 100644 index 000000000..53ef26fa3 --- /dev/null +++ b/dbaccess/source/ui/misc/defaultobjectnamecheck.cxx @@ -0,0 +1,160 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <core_resource.hxx> +#include <defaultobjectnamecheck.hxx> + +#include <strings.hrc> + +#include <com/sun/star/lang/IllegalArgumentException.hpp> +#include <com/sun/star/sdb/CommandType.hpp> +#include <com/sun/star/sdb/tools/XConnectionTools.hpp> +#include <com/sun/star/sdbc/SQLException.hpp> + +#include <connectivity/dbexception.hxx> +#include <connectivity/dbmetadata.hxx> + +#include <rtl/ustrbuf.hxx> + +#include <tools/diagnose_ex.h> +#include <cppuhelper/exc_hlp.hxx> + +#include <memory> +#include <string_view> + +namespace dbaui +{ + + using ::com::sun::star::uno::Reference; + using ::com::sun::star::lang::IllegalArgumentException; + using ::com::sun::star::container::XHierarchicalNameAccess; + using ::com::sun::star::sdbc::SQLException; + using ::com::sun::star::uno::Exception; + using ::com::sun::star::sdbc::XConnection; + using ::com::sun::star::sdb::tools::XObjectNames; + using ::com::sun::star::sdb::tools::XConnectionTools; + using ::com::sun::star::uno::UNO_QUERY; + + using namespace dbtools; + + namespace CommandType = ::com::sun::star::sdb::CommandType; + + // helper + namespace + { + void lcl_fillNameExistsError( std::u16string_view _rObjectName, SQLExceptionInfo& _out_rErrorToDisplay ) + { + SQLException aError; + OUString sErrorMessage = DBA_RES(STR_NAMED_OBJECT_ALREADY_EXISTS); + aError.Message = sErrorMessage.replaceAll("$#$", _rObjectName); + _out_rErrorToDisplay = aError; + } + + } + + // HierarchicalNameCheck_Impl + struct HierarchicalNameCheck_Impl + { + Reference< XHierarchicalNameAccess > xHierarchicalNames; + OUString sRelativeRoot; + }; + + // HierarchicalNameCheck + HierarchicalNameCheck::HierarchicalNameCheck( const Reference< XHierarchicalNameAccess >& _rxNames, const OUString& _rRelativeRoot ) + :m_pImpl( new HierarchicalNameCheck_Impl ) + { + m_pImpl->xHierarchicalNames = _rxNames; + m_pImpl->sRelativeRoot = _rRelativeRoot; + + if ( !m_pImpl->xHierarchicalNames.is() ) + throw IllegalArgumentException(); + } + + HierarchicalNameCheck::~HierarchicalNameCheck() + { + } + + bool HierarchicalNameCheck::isNameValid( const OUString& _rObjectName, SQLExceptionInfo& _out_rErrorToDisplay ) const + { + try + { + OUStringBuffer aCompleteName; + if ( !m_pImpl->sRelativeRoot.isEmpty() ) + { + aCompleteName.append( m_pImpl->sRelativeRoot ); + aCompleteName.append( "/" ); + } + aCompleteName.append( _rObjectName ); + + OUString sCompleteName( aCompleteName.makeStringAndClear() ); + if ( !m_pImpl->xHierarchicalNames->hasByHierarchicalName( sCompleteName ) ) + return true; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + lcl_fillNameExistsError( _rObjectName, _out_rErrorToDisplay ); + return false; + } + + // DynamicTableOrQueryNameCheck_Impl + struct DynamicTableOrQueryNameCheck_Impl + { + sal_Int32 nCommandType; + Reference< XObjectNames > xObjectNames; + }; + + // DynamicTableOrQueryNameCheck + DynamicTableOrQueryNameCheck::DynamicTableOrQueryNameCheck( const Reference< XConnection >& _rxSdbLevelConnection, sal_Int32 _nCommandType ) + :m_pImpl( new DynamicTableOrQueryNameCheck_Impl ) + { + Reference< XConnectionTools > xConnTools( _rxSdbLevelConnection, UNO_QUERY ); + if ( xConnTools.is() ) + m_pImpl->xObjectNames.set( xConnTools->getObjectNames() ); + if ( !m_pImpl->xObjectNames.is() ) + throw IllegalArgumentException(); + + if ( ( _nCommandType != CommandType::QUERY ) && ( _nCommandType != CommandType::TABLE ) ) + throw IllegalArgumentException(); + m_pImpl->nCommandType = _nCommandType; + } + + DynamicTableOrQueryNameCheck::~DynamicTableOrQueryNameCheck() + { + } + + bool DynamicTableOrQueryNameCheck::isNameValid( const OUString& _rObjectName, ::dbtools::SQLExceptionInfo& _out_rErrorToDisplay ) const + { + try + { + m_pImpl->xObjectNames->checkNameForCreate( m_pImpl->nCommandType, _rObjectName ); + return true; + } + catch( const SQLException& ) + { + _out_rErrorToDisplay = ::dbtools::SQLExceptionInfo( ::cppu::getCaughtException() ); + } + return false; + } + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/misc/dsmeta.cxx b/dbaccess/source/ui/misc/dsmeta.cxx new file mode 100644 index 000000000..286ce63aa --- /dev/null +++ b/dbaccess/source/ui/misc/dsmeta.cxx @@ -0,0 +1,182 @@ +/* -*- 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 <dsmeta.hxx> +#include <connectivity/DriversConfig.hxx> +#include <dsntypes.hxx> +#include <comphelper/processfactory.hxx> + +#include <map> +#include <utility> + +namespace dbaui +{ + + using namespace dbaccess; + using namespace ::com::sun::star; + + namespace { + + struct FeatureSupport + { + // authentication mode of the data source + AuthenticationMode eAuthentication; + + FeatureSupport() + :eAuthentication( AuthUserPwd ) + { + } + + explicit FeatureSupport(AuthenticationMode Auth) + :eAuthentication( Auth ) + { + } + }; + + struct FeatureMapping + { + /// one of the items from dsitems.hxx + ItemID nItemID; + OUString pAsciiFeatureName; + }; + + // global tables + const FeatureMapping s_aMappings[] = { + { DSID_AUTORETRIEVEENABLED, "GeneratedValues" }, + { DSID_AUTOINCREMENTVALUE, "GeneratedValues" }, + { DSID_AUTORETRIEVEVALUE, "GeneratedValues" }, + { DSID_SQL92CHECK, "UseSQL92NamingConstraints" }, + { DSID_APPEND_TABLE_ALIAS, "AppendTableAliasInSelect" }, + { DSID_AS_BEFORE_CORRNAME, "UseKeywordAsBeforeAlias" }, + { DSID_ENABLEOUTERJOIN, "UseBracketedOuterJoinSyntax" }, + { DSID_IGNOREDRIVER_PRIV, "IgnoreDriverPrivileges" }, + { DSID_PARAMETERNAMESUBST, "ParameterNameSubstitution" }, + { DSID_SUPPRESSVERSIONCL, "DisplayVersionColumns" }, + { DSID_CATALOG, "UseCatalogInSelect" }, + { DSID_SCHEMA, "UseSchemaInSelect" }, + { DSID_INDEXAPPENDIX, "UseIndexDirectionKeyword" }, + { DSID_DOSLINEENDS, "UseDOSLineEnds" }, + { DSID_BOOLEANCOMPARISON, "BooleanComparisonMode" }, + { DSID_CHECK_REQUIRED_FIELDS, "FormsCheckRequiredFields" }, + { DSID_IGNORECURRENCY, "IgnoreCurrency" }, + { DSID_ESCAPE_DATETIME, "EscapeDateTime" }, + { DSID_PRIMARY_KEY_SUPPORT, "PrimaryKeySupport" }, + { DSID_RESPECTRESULTSETTYPE, "RespectDriverResultSetType" }, + { DSID_MAX_ROW_SCAN, "MaxRowScan" }, + }; + } + + static const FeatureSet& lcl_getFeatureSet( const OUString& _rURL ) + { + typedef std::map< OUString, FeatureSet > FeatureSets; + static FeatureSets s_aFeatureSets = []() + { + FeatureSets tmp; + ::connectivity::DriversConfig aDriverConfig( ::comphelper::getProcessComponentContext() ); + const uno::Sequence< OUString > aPatterns = aDriverConfig.getURLs(); + for ( auto const & pattern : aPatterns ) + { + FeatureSet aCurrentSet; + const ::comphelper::NamedValueCollection aCurrentFeatures( aDriverConfig.getFeatures( pattern ).getNamedValues() ); + + for ( const FeatureMapping& rFeatureMapping : s_aMappings ) + { + if ( aCurrentFeatures.has( rFeatureMapping.pAsciiFeatureName ) ) + aCurrentSet.put( rFeatureMapping.nItemID ); + } + + tmp[ pattern ] = aCurrentSet; + } + return tmp; + }(); + + OSL_ENSURE( s_aFeatureSets.find( _rURL ) != s_aFeatureSets.end(), "invalid URL/pattern!" ); + return s_aFeatureSets[ _rURL ]; + } + + static AuthenticationMode getAuthenticationMode( const OUString& _sURL ) + { + static std::map< OUString, FeatureSupport > s_aSupport = []() + { + std::map< OUString, FeatureSupport > tmp; + ::connectivity::DriversConfig aDriverConfig(::comphelper::getProcessComponentContext()); + const uno::Sequence< OUString > aURLs = aDriverConfig.getURLs(); + const OUString* pIter = aURLs.getConstArray(); + const OUString* pEnd = pIter + aURLs.getLength(); + for(;pIter != pEnd;++pIter) + { + FeatureSupport aInit( AuthNone ); + const ::comphelper::NamedValueCollection& aMetaData = aDriverConfig.getMetaData(*pIter); + if ( aMetaData.has("Authentication") ) + { + OUString sAuth; + aMetaData.get("Authentication") >>= sAuth; + if ( sAuth == "UserPassword" ) + aInit = FeatureSupport(AuthUserPwd); + else if ( sAuth == "Password" ) + aInit = FeatureSupport(AuthPwd); + } + tmp.insert(std::make_pair(*pIter,aInit)); + } + return tmp; + }(); + OSL_ENSURE(s_aSupport.find(_sURL) != s_aSupport.end(),"Illegal URL!"); + return s_aSupport[ _sURL ].eAuthentication; + } + + // DataSourceMetaData_Impl + class DataSourceMetaData_Impl + { + public: + explicit DataSourceMetaData_Impl(const OUString& rURL); + + const OUString& getType() const { return m_sURL; } + + private: + const OUString m_sURL; + }; + + DataSourceMetaData_Impl::DataSourceMetaData_Impl( const OUString& _sURL ) + :m_sURL( _sURL ) + { + } + + // DataSourceMetaData + DataSourceMetaData::DataSourceMetaData( const OUString& _sURL ) + :m_pImpl( std::make_shared<DataSourceMetaData_Impl>( _sURL ) ) + { + } + + DataSourceMetaData::~DataSourceMetaData() + { + } + + const FeatureSet& DataSourceMetaData::getFeatureSet() const + { + return lcl_getFeatureSet( m_pImpl->getType() ); + } + + AuthenticationMode DataSourceMetaData::getAuthentication( const OUString& _sURL ) + { + return getAuthenticationMode( _sURL ); + } + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/misc/imageprovider.cxx b/dbaccess/source/ui/misc/imageprovider.cxx new file mode 100644 index 000000000..b69ec70e6 --- /dev/null +++ b/dbaccess/source/ui/misc/imageprovider.cxx @@ -0,0 +1,202 @@ +/* -*- 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 <imageprovider.hxx> +#include <bitmaps.hlst> + +#include <com/sun/star/graphic/GraphicColorMode.hpp> +#include <com/sun/star/sdb/application/XTableUIProvider.hpp> +#include <com/sun/star/sdb/application/DatabaseObject.hpp> +#include <com/sun/star/sdbcx/XViewsSupplier.hpp> + +#include <tools/diagnose_ex.h> + +namespace dbaui +{ + + using ::com::sun::star::uno::Reference; + using ::com::sun::star::sdbc::XConnection; + using ::com::sun::star::uno::Exception; + using ::com::sun::star::container::XNameAccess; + using ::com::sun::star::graphic::XGraphic; + using ::com::sun::star::sdb::application::XTableUIProvider; + using ::com::sun::star::uno::UNO_QUERY; + using ::com::sun::star::sdbcx::XViewsSupplier; + using ::com::sun::star::uno::UNO_SET_THROW; + + namespace GraphicColorMode = css::graphic::GraphicColorMode; + namespace DatabaseObject = css::sdb::application::DatabaseObject; + + // ImageProvider_Data + struct ImageProvider_Data + { + /// the connection we work with + Reference< XConnection > xConnection; + /// the views of the connection, if the DB supports views + Reference< XNameAccess > xViews; + /// interface for providing table's UI + Reference< XTableUIProvider > xTableUI; + }; + + namespace + { + void lcl_getConnectionProvidedTableIcon_nothrow( const ImageProvider_Data& _rData, + const OUString& _rName, Reference< XGraphic >& _out_rxGraphic ) + { + try + { + if ( _rData.xTableUI.is() ) + _out_rxGraphic = _rData.xTableUI->getTableIcon( _rName, GraphicColorMode::NORMAL ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + + void lcl_getTableImageResourceID_nothrow( const ImageProvider_Data& _rData, const OUString& _rName, + OUString& _out_rResourceID) + { + _out_rResourceID = OUString(); + try + { + bool bIsView = _rData.xViews.is() && _rData.xViews->hasByName( _rName ); + if ( bIsView ) + { + _out_rResourceID = VIEW_TREE_ICON; + } + else + { + _out_rResourceID = TABLE_TREE_ICON; + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + } + // ImageProvider + ImageProvider::ImageProvider() + :m_pData( std::make_shared<ImageProvider_Data>() ) + { + } + + ImageProvider::ImageProvider( const Reference< XConnection >& _rxConnection ) + :m_pData( std::make_shared<ImageProvider_Data>() ) + { + m_pData->xConnection = _rxConnection; + try + { + Reference< XViewsSupplier > xSuppViews( m_pData->xConnection, UNO_QUERY ); + if ( xSuppViews.is() ) + m_pData->xViews.set( xSuppViews->getViews(), UNO_SET_THROW ); + + m_pData->xTableUI.set( _rxConnection, UNO_QUERY ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + + OUString ImageProvider::getImageId(const OUString& _rName, const sal_Int32 _nDatabaseObjectType) + { + if (_nDatabaseObjectType != DatabaseObject::TABLE) + { + // for types other than tables, the icon does not depend on the concrete object + return getDefaultImageResourceID( _nDatabaseObjectType ); + } + else + { + // no -> determine by type + OUString sImageResourceID; + lcl_getTableImageResourceID_nothrow( *m_pData, _rName, sImageResourceID ); + return sImageResourceID; + } + } + + Reference<XGraphic> ImageProvider::getXGraphic(const OUString& _rName, const sal_Int32 _nDatabaseObjectType) + { + Reference<XGraphic> xGraphic; + if (_nDatabaseObjectType == DatabaseObject::TABLE) + { + // check whether the connection can give us an icon + lcl_getConnectionProvidedTableIcon_nothrow( *m_pData, _rName, xGraphic ); + } + return xGraphic; + } + + OUString ImageProvider::getDefaultImageResourceID( sal_Int32 _nDatabaseObjectType) + { + OUString sImageResourceID; + switch ( _nDatabaseObjectType ) + { + case DatabaseObject::QUERY: + sImageResourceID = QUERY_TREE_ICON; + break; + case DatabaseObject::FORM: + sImageResourceID = FORM_TREE_ICON; + break; + case DatabaseObject::REPORT: + sImageResourceID = REPORT_TREE_ICON; + break; + case DatabaseObject::TABLE: + sImageResourceID = TABLE_TREE_ICON; + break; + default: + OSL_FAIL( "ImageProvider::getDefaultImage: invalid database object type!" ); + break; + } + return sImageResourceID; + } + + OUString ImageProvider::getFolderImageId( sal_Int32 _nDatabaseObjectType ) + { + OUString sImageResourceID; + switch ( _nDatabaseObjectType ) + { + case DatabaseObject::QUERY: + sImageResourceID = QUERYFOLDER_TREE_ICON; + break; + case DatabaseObject::FORM: + sImageResourceID = FORMFOLDER_TREE_ICON; + break; + case DatabaseObject::REPORT: + sImageResourceID = REPORTFOLDER_TREE_ICON; + break; + case DatabaseObject::TABLE: + sImageResourceID = TABLEFOLDER_TREE_ICON; + break; + default: + OSL_FAIL( "ImageProvider::getDefaultImage: invalid database object type!" ); + break; + } + + return sImageResourceID; + } + + OUString ImageProvider::getDatabaseImage() + { + return DATABASE_TREE_ICON; + } + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/misc/indexcollection.cxx b/dbaccess/source/ui/misc/indexcollection.cxx new file mode 100644 index 000000000..1b9377362 --- /dev/null +++ b/dbaccess/source/ui/misc/indexcollection.cxx @@ -0,0 +1,328 @@ +/* -*- 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 <indexcollection.hxx> +#include <tools/diagnose_ex.h> +#include <com/sun/star/sdbc/SQLException.hpp> +#include <com/sun/star/sdbcx/XAppend.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/sdbcx/XColumnsSupplier.hpp> +#include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp> +#include <comphelper/extract.hxx> +#include <com/sun/star/sdbcx/XDrop.hpp> + +namespace dbaui +{ + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::container; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::sdbcx; + using namespace ::com::sun::star::sdbc; + + // OIndexCollection + OIndexCollection::OIndexCollection() + { + } + + OIndexCollection::OIndexCollection(const OIndexCollection& _rSource) + { + *this = _rSource; + } + + OIndexCollection& OIndexCollection::operator=(const OIndexCollection& _rSource) + { + detach(); + m_xIndexes = _rSource.m_xIndexes; + m_aIndexes = _rSource.m_aIndexes; + return *this; + } + + void OIndexCollection::attach(const Reference< XNameAccess >& _rxIndexes) + { + implConstructFrom(_rxIndexes); + } + + void OIndexCollection::detach() + { + m_xIndexes.clear(); + m_aIndexes.clear(); + } + + Indexes::const_iterator OIndexCollection::find(const OUString& _rName) const + { + // loop'n'compare + return std::find_if(m_aIndexes.cbegin(), m_aIndexes.cend(), + [&_rName](const OIndex& rIndex) { return rIndex.sName == _rName; }); + } + + Indexes::iterator OIndexCollection::find(const OUString& _rName) + { + // loop'n'compare + return std::find_if(m_aIndexes.begin(), m_aIndexes.end(), + [&_rName](const OIndex& rIndex) { return rIndex.sName == _rName; }); + } + + Indexes::const_iterator OIndexCollection::findOriginal(const OUString& _rName) const + { + // loop'n'compare + return std::find_if(m_aIndexes.cbegin(), m_aIndexes.cend(), + [&_rName](const OIndex& rIndex) { return rIndex.getOriginalName() == _rName; }); + } + + Indexes::iterator OIndexCollection::findOriginal(const OUString& _rName) + { + // loop'n'compare + return std::find_if(m_aIndexes.begin(), m_aIndexes.end(), + [&_rName](const OIndex& rIndex) { return rIndex.getOriginalName() == _rName; }); + } + + void OIndexCollection::commitNewIndex(const Indexes::iterator& _rPos) + { + OSL_ENSURE(_rPos->isNew(), "OIndexCollection::commitNewIndex: index must be new!"); + + try + { + Reference< XDataDescriptorFactory > xIndexFactory(m_xIndexes, UNO_QUERY); + Reference< XAppend > xAppendIndex(xIndexFactory, UNO_QUERY); + if (!xAppendIndex.is()) + { + OSL_FAIL("OIndexCollection::commitNewIndex: missing an interface of the index container!"); + return; + } + + Reference< XPropertySet > xIndexDescriptor = xIndexFactory->createDataDescriptor(); + Reference< XColumnsSupplier > xColsSupp(xIndexDescriptor, UNO_QUERY); + Reference< XNameAccess > xCols; + if (xColsSupp.is()) + xCols = xColsSupp->getColumns(); + + Reference< XDataDescriptorFactory > xColumnFactory(xCols, UNO_QUERY); + Reference< XAppend > xAppendCols(xColumnFactory, UNO_QUERY); + if (!xAppendCols.is()) + { + OSL_FAIL("OIndexCollection::commitNewIndex: invalid index descriptor returned!"); + return; + } + + // set the properties + static constexpr OUStringLiteral s_sNamePropertyName = u"Name"; + // the index' own props + xIndexDescriptor->setPropertyValue("IsUnique", css::uno::Any(_rPos->bUnique)); + xIndexDescriptor->setPropertyValue(s_sNamePropertyName, Any(_rPos->sName)); + + // the fields + for (auto const& field : _rPos->aFields) + { + OSL_ENSURE(!xCols->hasByName(field.sFieldName), "OIndexCollection::commitNewIndex: double column name (need to prevent this outside)!"); + + Reference< XPropertySet > xColDescriptor = xColumnFactory->createDataDescriptor(); + OSL_ENSURE(xColDescriptor.is(), "OIndexCollection::commitNewIndex: invalid column descriptor!"); + if (xColDescriptor.is()) + { + xColDescriptor->setPropertyValue("IsAscending", css::uno::Any(field.bSortAscending)); + xColDescriptor->setPropertyValue(s_sNamePropertyName, Any(field.sFieldName)); + xAppendCols->appendByDescriptor(xColDescriptor); + } + } + + xAppendIndex->appendByDescriptor(xIndexDescriptor); + + _rPos->flagAsCommitted(GrantIndexAccess()); + _rPos->clearModified(); + } + catch(SQLException&) + { // allowed to pass + throw; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + + bool OIndexCollection::dropNoRemove(const Indexes::iterator& _rPos) + { + try + { + OSL_ENSURE(m_xIndexes->hasByName(_rPos->getOriginalName()), "OIndexCollection::drop: invalid name!"); + + Reference< XDrop > xDropIndex(m_xIndexes, UNO_QUERY); + if (!xDropIndex.is()) + { + OSL_FAIL("OIndexCollection::drop: no XDrop interface!"); + return false; + } + + xDropIndex->dropByName(_rPos->getOriginalName()); + } + catch(SQLException&) + { // allowed to pass + throw; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + return false; + } + + // adjust the OIndex structure + Indexes::iterator aDropped = findOriginal(_rPos->getOriginalName()); + OSL_ENSURE(aDropped != m_aIndexes.end(), "OIndexCollection::drop: invalid original name, but successful commit?!"); + aDropped->flagAsNew(GrantIndexAccess()); + + return true; + } + + bool OIndexCollection::drop(const Indexes::iterator& _rPos) + { + OSL_ENSURE((_rPos >= m_aIndexes.begin()) && (_rPos < m_aIndexes.end()), + "OIndexCollection::drop: invalid position (fasten your seatbelt... this will crash)!"); + + if (!_rPos->isNew()) + if (!dropNoRemove(_rPos)) + return false; + + // adjust the index array + m_aIndexes.erase(_rPos); + return true; + } + + void OIndexCollection::implFillIndexInfo(OIndex& _rIndex) + { + // get the UNO descriptor for the index + Reference< XPropertySet > xIndex; + m_xIndexes->getByName(_rIndex.getOriginalName()) >>= xIndex; + if (!xIndex.is()) + { + OSL_FAIL("OIndexCollection::implFillIndexInfo: got an invalid index object!"); + } + else + implFillIndexInfo(_rIndex, xIndex); + } + + void OIndexCollection::implFillIndexInfo(OIndex& _rIndex, const Reference< XPropertySet >& _rxDescriptor) + { + _rIndex.bPrimaryKey = ::cppu::any2bool(_rxDescriptor->getPropertyValue("IsPrimaryKeyIndex")); + _rIndex.bUnique = ::cppu::any2bool(_rxDescriptor->getPropertyValue("IsUnique")); + _rxDescriptor->getPropertyValue("Catalog") >>= _rIndex.sDescription; + + // the columns + Reference< XColumnsSupplier > xSuppCols(_rxDescriptor, UNO_QUERY); + Reference< XNameAccess > xCols; + if (xSuppCols.is()) + xCols = xSuppCols->getColumns(); + OSL_ENSURE(xCols.is(), "OIndexCollection::implFillIndexInfo: the index does not have columns!"); + if (!xCols.is()) + return; + + Sequence< OUString > aFieldNames = xCols->getElementNames(); + _rIndex.aFields.resize(aFieldNames.getLength()); + + const OUString* pFieldNames = aFieldNames.getConstArray(); + const OUString* pFieldNamesEnd = pFieldNames + aFieldNames.getLength(); + IndexFields::iterator aCopyTo = _rIndex.aFields.begin(); + + Reference< XPropertySet > xIndexColumn; + for (;pFieldNames < pFieldNamesEnd; ++pFieldNames, ++aCopyTo) + { + // extract the column + xIndexColumn.clear(); + xCols->getByName(*pFieldNames) >>= xIndexColumn; + if (!xIndexColumn.is()) + { + OSL_FAIL("OIndexCollection::implFillIndexInfo: invalid index column!"); + --aCopyTo; + continue; + } + + // get the relevant properties + aCopyTo->sFieldName = *pFieldNames; + aCopyTo->bSortAscending = ::cppu::any2bool(xIndexColumn->getPropertyValue("IsAscending")); + } + + _rIndex.aFields.resize(aCopyTo - _rIndex.aFields.begin()); + // (just in case some fields were invalid ...) + } + + void OIndexCollection::resetIndex(const Indexes::iterator& _rPos) + { + OSL_ENSURE(_rPos >= m_aIndexes.begin() && _rPos < m_aIndexes.end(), + "OIndexCollection::resetIndex: invalid position!"); + + try + { + _rPos->sName = _rPos->getOriginalName(); + implFillIndexInfo(*_rPos); + + _rPos->clearModified(); + _rPos->flagAsCommitted(GrantIndexAccess()); + } + catch(SQLException&) + { // allowed to pass + throw; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + + Indexes::iterator OIndexCollection::insert(const OUString& _rName) + { + OSL_ENSURE(end() == find(_rName), "OIndexCollection::insert: invalid new name!"); + OIndex aNewIndex((OUString())); // the empty string indicates the index is a new one + aNewIndex.sName = _rName; + m_aIndexes.push_back(aNewIndex); + return m_aIndexes.end() - 1; // the last element is the new one ... + } + + void OIndexCollection::implConstructFrom(const Reference< XNameAccess >& _rxIndexes) + { + detach(); + + m_xIndexes = _rxIndexes; + if (!m_xIndexes.is()) + return; + + // loop through all the indexes + Sequence< OUString > aNames = m_xIndexes->getElementNames(); + const OUString* pNames = aNames.getConstArray(); + const OUString* pEnd = pNames + aNames.getLength(); + for (; pNames < pEnd; ++pNames) + { + // extract the index object + Reference< XPropertySet > xIndex; + m_xIndexes->getByName(*pNames) >>= xIndex; + if (!xIndex.is()) + { + OSL_FAIL("OIndexCollection::implConstructFrom: got an invalid index object ... ignoring!"); + continue; + } + + // fill the OIndex structure + OIndex aCurrentIndex(*pNames); + implFillIndexInfo(aCurrentIndex); + m_aIndexes.push_back(aCurrentIndex); + } + } + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/misc/linkeddocuments.cxx b/dbaccess/source/ui/misc/linkeddocuments.cxx new file mode 100644 index 000000000..192331ced --- /dev/null +++ b/dbaccess/source/ui/misc/linkeddocuments.cxx @@ -0,0 +1,354 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <core_resource.hxx> +#include <linkeddocuments.hxx> +#include <osl/diagnose.h> +#include <tools/diagnose_ex.h> +#include <unotools/confignode.hxx> +#include <comphelper/classids.hxx> +#include <comphelper/namedvaluecollection.hxx> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/frame/XComponentLoader.hpp> +#include <com/sun/star/sdbc/SQLException.hpp> +#include <com/sun/star/ucb/XCommandProcessor.hpp> +#include <com/sun/star/ucb/OpenCommandArgument.hpp> +#include <com/sun/star/ucb/OpenMode.hpp> +#include <com/sun/star/task/XJobExecutor.hpp> +#include <comphelper/types.hxx> +#include <strings.hrc> +#include <strings.hxx> +#include <svl/filenotation.hxx> +#include <browserids.hxx> +#include <com/sun/star/container/XHierarchicalNameContainer.hpp> +#include <comphelper/mimeconfighelper.hxx> +#include <vcl/weld.hxx> + +#include <cppuhelper/exc_hlp.hxx> +#include <connectivity/dbtools.hxx> +#include <com/sun/star/io/WrongFormatException.hpp> + +namespace dbaui +{ + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::container; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::frame; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::util; + using namespace ::com::sun::star::ucb; + using namespace ::com::sun::star::sdbc; + using namespace ::com::sun::star::sdb::application; + using namespace ::com::sun::star::task; + using namespace ::svt; + + namespace + { + Sequence< sal_Int8 > lcl_GetSequenceClassID( sal_uInt32 n1, sal_uInt16 n2, sal_uInt16 n3, + sal_uInt8 b8, sal_uInt8 b9, sal_uInt8 b10, sal_uInt8 b11, + sal_uInt8 b12, sal_uInt8 b13, sal_uInt8 b14, sal_uInt8 b15 ) + { + Sequence< sal_Int8 > aResult{ /* [ 0] */ static_cast<sal_Int8>(n1 >> 24), + /* [ 1] */ static_cast<sal_Int8>(( n1 << 8 ) >> 24), + /* [ 2] */ static_cast<sal_Int8>(( n1 << 16 ) >> 24), + /* [ 3] */ static_cast<sal_Int8>(( n1 << 24 ) >> 24), + /* [ 4] */ static_cast<sal_Int8>(n2 >> 8), + /* [ 5] */ static_cast<sal_Int8>(( n2 << 8 ) >> 8), + /* [ 6] */ static_cast<sal_Int8>(n3 >> 8), + /* [ 7] */ static_cast<sal_Int8>(( n3 << 8 ) >> 8), + /* [ 8] */ static_cast<sal_Int8>(b8), + /* [ 9] */ static_cast<sal_Int8>(b9), + /* [10] */ static_cast<sal_Int8>(b10), + /* [11] */ static_cast<sal_Int8>(b11), + /* [12] */ static_cast<sal_Int8>(b12), + /* [13] */ static_cast<sal_Int8>(b13), + /* [14] */ static_cast<sal_Int8>(b14), + /* [15] */ static_cast<sal_Int8>(b15) }; + return aResult; + } + } + + // OLinkedDocumentsAccess + OLinkedDocumentsAccess::OLinkedDocumentsAccess( weld::Window* pDialogParent, const Reference< XDatabaseDocumentUI >& i_rDocumentUI, + const Reference< XComponentContext >& _rxContext, const Reference< XNameAccess >& _rxContainer, + const Reference< XConnection>& _xConnection, const OUString& _sDataSourceName ) + :m_xContext(_rxContext) + ,m_xDocumentContainer(_rxContainer) + ,m_xConnection(_xConnection) + ,m_xDocumentUI( i_rDocumentUI ) + ,m_pDialogParent(pDialogParent) + ,m_sDataSourceName(_sDataSourceName) + { + OSL_ENSURE(m_xContext.is(), "OLinkedDocumentsAccess::OLinkedDocumentsAccess: invalid service factory!"); + assert(m_pDialogParent && "OLinkedDocumentsAccess::OLinkedDocumentsAccess: really need a dialog parent!"); + } + OLinkedDocumentsAccess::~OLinkedDocumentsAccess() + { + } + Reference< XComponent> OLinkedDocumentsAccess::impl_open( const OUString& _rLinkName, Reference< XComponent >& _xDefinition, + ElementOpenMode _eOpenMode, const ::comphelper::NamedValueCollection& _rAdditionalArgs ) + { + Reference< XComponent> xRet; + OSL_ENSURE(m_xDocumentContainer.is(), "OLinkedDocumentsAccess::OLinkedDocumentsAccess: invalid document container!"); + Reference< XComponentLoader > xComponentLoader(m_xDocumentContainer,UNO_QUERY); + if ( !xComponentLoader.is() ) + return xRet; + + weld::WaitObject aWaitCursor(m_pDialogParent); + + ::comphelper::NamedValueCollection aArguments; + OUString sOpenMode; + switch ( _eOpenMode ) + { + case E_OPEN_NORMAL: + sOpenMode = "open"; + break; + + case E_OPEN_FOR_MAIL: + aArguments.put( "Hidden", true ); + [[fallthrough]]; + + case E_OPEN_DESIGN: + sOpenMode = "openDesign"; + break; + + default: + OSL_FAIL( "OLinkedDocumentsAccess::implOpen: invalid open mode!" ); + break; + } + aArguments.put( "OpenMode", sOpenMode ); + + aArguments.put( PROPERTY_ACTIVE_CONNECTION, m_xConnection ); + + Reference<XHierarchicalNameContainer> xHier(m_xDocumentContainer,UNO_QUERY); + if ( xHier.is() && xHier->hasByHierarchicalName(_rLinkName) ) + { + _xDefinition.set(xHier->getByHierarchicalName(_rLinkName),UNO_QUERY); + } + + aArguments.merge( _rAdditionalArgs, true ); + + xRet = xComponentLoader->loadComponentFromURL( _rLinkName, OUString(), 0, aArguments.getPropertyValues() ); + + return xRet; + } + void OLinkedDocumentsAccess::impl_newWithPilot( const char* _pWizardService, + const sal_Int32 _nCommandType, const OUString& _rObjectName ) + { + try + { + ::comphelper::NamedValueCollection aArgs; + aArgs.put( "DataSourceName", m_sDataSourceName ); + + if ( m_xConnection.is() ) + aArgs.put( "ActiveConnection", m_xConnection ); + + if ( !_rObjectName.isEmpty() && ( _nCommandType != -1 ) ) + { + aArgs.put( "CommandType", _nCommandType ); + aArgs.put( "Command", _rObjectName ); + } + + aArgs.put( "DocumentUI", m_xDocumentUI ); + + Reference< XJobExecutor > xWizard; + { + weld::WaitObject aWaitCursor(m_pDialogParent); + xWizard.set( m_xContext->getServiceManager()->createInstanceWithArgumentsAndContext( + OUString::createFromAscii( _pWizardService ), + aArgs.getWrappedPropertyValues(), + m_xContext + ), UNO_QUERY_THROW ); + } + + xWizard->trigger( "start" ); + ::comphelper::disposeComponent( xWizard ); + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + void OLinkedDocumentsAccess::newFormWithPilot( const sal_Int32 _nCommandType,const OUString& _rObjectName ) + { + impl_newWithPilot( "com.sun.star.wizards.form.CallFormWizard", _nCommandType, _rObjectName ); + } + + void OLinkedDocumentsAccess::newReportWithPilot( const sal_Int32 _nCommandType, const OUString& _rObjectName ) + { + impl_newWithPilot( "com.sun.star.wizards.report.CallReportWizard", _nCommandType, _rObjectName ); + } + void OLinkedDocumentsAccess::newTableWithPilot() + { + impl_newWithPilot( "com.sun.star.wizards.table.CallTableWizard", -1, OUString() ); + } + void OLinkedDocumentsAccess::newQueryWithPilot() + { + impl_newWithPilot( "com.sun.star.wizards.query.CallQueryWizard", -1, OUString() ); + } + Reference< XComponent > OLinkedDocumentsAccess::newDocument( sal_Int32 i_nActionID, + const ::comphelper::NamedValueCollection& i_rCreationArgs, Reference< XComponent >& o_rDefinition ) + { + OSL_ENSURE(m_xDocumentContainer.is(), "OLinkedDocumentsAccess::newDocument: invalid document container!"); + // determine the class ID to use for the new document + Sequence<sal_Int8> aClassId; + if ( !i_rCreationArgs.has( "ClassID" ) + && !i_rCreationArgs.has( "MediaType" ) + && !i_rCreationArgs.has( "DocumentServiceName" ) + ) + { + switch ( i_nActionID ) + { + case ID_FORM_NEW_TEXT: + aClassId = lcl_GetSequenceClassID(SO3_SW_CLASSID); + OSL_ENSURE(aClassId == comphelper::MimeConfigurationHelper::GetSequenceClassID(SO3_SW_CLASSID),"Not equal"); + break; + + case ID_FORM_NEW_CALC: + aClassId = lcl_GetSequenceClassID(SO3_SC_CLASSID); + break; + + case ID_FORM_NEW_IMPRESS: + aClassId = lcl_GetSequenceClassID(SO3_SIMPRESS_CLASSID); + break; + + case ID_REPORT_NEW_TEXT: + aClassId = comphelper::MimeConfigurationHelper::GetSequenceClassID(SO3_RPT_CLASSID_90); + break; + + default: + OSL_FAIL( "OLinkedDocumentsAccess::newDocument: please use newFormWithPilot!" ); + return Reference< XComponent >(); + + } + } + + // load the document as template + Reference< XComponent > xNewDocument; + try + { // get the desktop object + + Reference<XMultiServiceFactory> xORB(m_xDocumentContainer,UNO_QUERY); + if ( xORB.is() ) + { + ::comphelper::NamedValueCollection aCreationArgs( i_rCreationArgs ); + if ( aClassId.hasElements() ) + aCreationArgs.put( "ClassID", aClassId ); + aCreationArgs.put( PROPERTY_ACTIVE_CONNECTION, m_xConnection ); + + // separate values which are real creation args from args relevant for opening the doc + ::comphelper::NamedValueCollection aCommandArgs; + if ( aCreationArgs.has( "Hidden" ) ) + { + aCommandArgs.put( "Hidden", aCreationArgs.get( "Hidden" ) ); + aCreationArgs.remove( "Hidden" ); + } + + Reference< XCommandProcessor > xContent( xORB->createInstanceWithArguments( + SERVICE_SDB_DOCUMENTDEFINITION, + aCreationArgs.getWrappedPropertyValues() + ), + UNO_QUERY_THROW + ); + o_rDefinition.set( xContent, UNO_QUERY ); + + // put the OpenMode into the OpenArgs + OpenCommandArgument aOpenModeArg; + aOpenModeArg.Mode = OpenMode::DOCUMENT; + aCommandArgs.put( "OpenMode", aOpenModeArg ); + + Command aCommand; + aCommand.Name = "openDesign"; + aCommand.Argument <<= aCommandArgs.getPropertyValues(); + weld::WaitObject aWaitCursor(m_pDialogParent); + xNewDocument.set( xContent->execute( aCommand, xContent->createCommandIdentifier(), nullptr ), UNO_QUERY ); + } + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + return xNewDocument; + } + + Reference< XComponent > OLinkedDocumentsAccess::open( const OUString& _rLinkName, Reference< XComponent >& _xDefinition, + ElementOpenMode _eOpenMode, const ::comphelper::NamedValueCollection& _rAdditionalArgs ) + { + dbtools::SQLExceptionInfo aInfo; + Reference< XComponent > xRet; + try + { + xRet = impl_open( _rLinkName, _xDefinition, _eOpenMode, _rAdditionalArgs ); + if ( !xRet.is() ) + { + OUString sMessage = DBA_RES(STR_COULDNOTOPEN_LINKEDDOC); + sMessage = sMessage.replaceFirst("$file$",_rLinkName); + + css::sdbc::SQLException aSQLException; + aSQLException.Message = sMessage; + aInfo = dbtools::SQLExceptionInfo(aSQLException); + } + } + catch(const css::io::WrongFormatException &e) + { + css::sdbc::SQLException aSQLException; + aSQLException.Message = e.Message; + aSQLException.Context = e.Context; + aInfo = dbtools::SQLExceptionInfo(aSQLException); + + // more like a hack, insert an empty message + OUString sText( DBA_RES( RID_STR_EXTENSION_NOT_PRESENT ) ); + sText = sText.replaceFirst("$file$",_rLinkName); + aInfo.prepend(sText); + + OUString sMessage = DBA_RES(STR_COULDNOTOPEN_LINKEDDOC); + sMessage = sMessage.replaceFirst("$file$",_rLinkName); + aInfo.prepend(sMessage); + } + catch(const Exception& e) + { + Any aAny = ::cppu::getCaughtException(); + css::sdbc::SQLException a; + if ( !(aAny >>= a) || (a.ErrorCode != dbtools::ParameterInteractionCancelled) ) + { + css::sdbc::SQLException aSQLException; + aSQLException.Message = e.Message; + aSQLException.Context = e.Context; + aInfo = dbtools::SQLExceptionInfo(aSQLException); + + // more like a hack, insert an empty message + aInfo.prepend(" \n"); + + OUString sMessage = DBA_RES(STR_COULDNOTOPEN_LINKEDDOC); + sMessage = sMessage.replaceFirst("$file$",_rLinkName); + aInfo.prepend(sMessage); + } + } + if (aInfo.isValid()) + { + showError(aInfo, m_pDialogParent->GetXWindow(), m_xContext); + } + return xRet; + } + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/misc/propertystorage.cxx b/dbaccess/source/ui/misc/propertystorage.cxx new file mode 100644 index 000000000..c3c504994 --- /dev/null +++ b/dbaccess/source/ui/misc/propertystorage.cxx @@ -0,0 +1,106 @@ +/* -*- 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 <propertystorage.hxx> + +#include <svl/itemset.hxx> +#include <svl/stritem.hxx> +#include <svl/eitem.hxx> + +#include <osl/diagnose.h> + +#include <cassert> +#include <memory> + +namespace dbaui +{ + + using ::com::sun::star::uno::Any; + + // helper + namespace + { + template < class ITEMTYPE, class UNOTYPE > + class ItemAdapter + { + public: + static bool trySet( SfxItemSet& _rSet, sal_uInt16 _nItemId, const Any& _rValue ) + { + const SfxPoolItem& rItem( _rSet.Get( _nItemId ) ); + const ITEMTYPE* pTypedItem = dynamic_cast< const ITEMTYPE* >( &rItem ); + if ( !pTypedItem ) + return false; + + UNOTYPE aValue( pTypedItem->GetValue() ); + OSL_VERIFY( _rValue >>= aValue ); + // TODO: one could throw an IllegalArgumentException here - finally, this method + // is (to be) used from within an XPropertySet::setPropertyValue implementation, + // where this would be the appropriate reaction on wrong value types + ITEMTYPE* pCloneItem = dynamic_cast< ITEMTYPE* >( pTypedItem->Clone() ); + if(!pCloneItem) + { + return false; + } + std::unique_ptr< ITEMTYPE > pClone( pCloneItem); + assert(pClone.get()); + pClone->SetValue( aValue ); + _rSet.Put( std::move(pClone) ); + return true; + } + + static bool tryGet( const SfxPoolItem& _rItem, Any& _out_rValue ) + { + const ITEMTYPE* pTypedItem = dynamic_cast< const ITEMTYPE* >( &_rItem ); + if ( !pTypedItem ) + return false; + + _out_rValue <<= UNOTYPE( pTypedItem->GetValue() ); + return true; + } + }; + } + + // SetItemPropertyStorage + void SetItemPropertyStorage::getPropertyValue( Any& _out_rValue ) const + { + const SfxPoolItem& rItem( m_rItemSet.Get( m_nItemID ) ); + + // try some known item types + if ( ItemAdapter< SfxBoolItem, bool >::tryGet( rItem, _out_rValue ) + || ItemAdapter< SfxStringItem, OUString >::tryGet( rItem, _out_rValue ) + ) + return; + + OSL_FAIL( "SetItemPropertyStorage::getPropertyValue: unsupported item type!" ); + } + + void SetItemPropertyStorage::setPropertyValue( const Any& _rValue ) + { + // try some known item types + if ( ItemAdapter< SfxBoolItem, bool >::trySet( m_rItemSet, m_nItemID, _rValue ) + || ItemAdapter< SfxStringItem, OUString >::trySet( m_rItemSet, m_nItemID, _rValue ) + ) + return; + + OSL_FAIL( "SetItemPropertyStorage::setPropertyValue: unsupported item type!" ); + } + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/misc/singledoccontroller.cxx b/dbaccess/source/ui/misc/singledoccontroller.cxx new file mode 100644 index 000000000..28b0c9e77 --- /dev/null +++ b/dbaccess/source/ui/misc/singledoccontroller.cxx @@ -0,0 +1,184 @@ +/* -*- 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 <dbaccess/dbaundomanager.hxx> +#include <dbaccess/dataview.hxx> +#include <core_resource.hxx> +#include <singledoccontroller.hxx> +#include <browserids.hxx> +#include <strings.hrc> + +#include <svl/undo.hxx> + +namespace dbaui +{ + + using ::com::sun::star::uno::Reference; + using ::com::sun::star::uno::Sequence; + using ::com::sun::star::uno::XComponentContext; + using ::com::sun::star::document::XUndoManager; + using ::com::sun::star::beans::PropertyValue; + + // OSingleDocumentController_Data + struct OSingleDocumentController_Data + { + // no Reference! see UndoManager::acquire + std::unique_ptr<UndoManager> m_pUndoManager; + + OSingleDocumentController_Data( ::cppu::OWeakObject& i_parent, ::osl::Mutex& i_mutex ) + : m_pUndoManager(new UndoManager(i_parent, i_mutex)) + { + } + }; + + // OSingleDocumentController + OSingleDocumentController::OSingleDocumentController( const Reference< XComponentContext >& _rxORB ) + :OSingleDocumentController_Base( _rxORB ) + ,m_pData( new OSingleDocumentController_Data( *this, getMutex() ) ) + { + } + + OSingleDocumentController::~OSingleDocumentController() + { + } + + void SAL_CALL OSingleDocumentController::disposing() + { + OSingleDocumentController_Base::disposing(); + ClearUndoManager(); + m_pData->m_pUndoManager->disposing(); + } + + void OSingleDocumentController::ClearUndoManager() + { + GetUndoManager().Clear(); + } + + SfxUndoManager& OSingleDocumentController::GetUndoManager() const + { + return m_pData->m_pUndoManager->GetSfxUndoManager(); + } + + void OSingleDocumentController::addUndoActionAndInvalidate(std::unique_ptr<SfxUndoAction> _pAction) + { + // add undo action + GetUndoManager().AddUndoAction( std::move(_pAction) ); + + // when we add an undo action the controller was modified + setModified( true ); + + // now inform me that or states changed + InvalidateFeature( ID_BROWSER_UNDO ); + InvalidateFeature( ID_BROWSER_REDO ); + } + + Reference< XUndoManager > SAL_CALL OSingleDocumentController::getUndoManager( ) + { + // see UndoManager::acquire + return m_pData->m_pUndoManager.get(); + } + + FeatureState OSingleDocumentController::GetState(sal_uInt16 _nId) const + { + FeatureState aReturn; + switch ( _nId ) + { + case ID_BROWSER_UNDO: + aReturn.bEnabled = isEditable() && GetUndoManager().GetUndoActionCount() != 0; + if ( aReturn.bEnabled ) + { + OUString sUndo = DBA_RES(STR_UNDO_COLON) + " " + + GetUndoManager().GetUndoActionComment(); + aReturn.sTitle = sUndo; + } + break; + + case ID_BROWSER_REDO: + aReturn.bEnabled = isEditable() && GetUndoManager().GetRedoActionCount() != 0; + if ( aReturn.bEnabled ) + { + OUString sRedo = DBA_RES(STR_REDO_COLON) + " " + + GetUndoManager().GetRedoActionComment(); + aReturn.sTitle = sRedo; + } + break; + + case SID_GETUNDOSTRINGS: + { + size_t nCount(GetUndoManager().GetUndoActionCount()); + Sequence<OUString> aSeq(nCount); + auto aSeqRange = asNonConstRange(aSeq); + for (size_t n = 0; n < nCount; ++n) + aSeqRange[n] = GetUndoManager().GetUndoActionComment(n); + aReturn.aValue <<= aSeq; + aReturn.bEnabled = true; + break; + } + + case SID_GETREDOSTRINGS: + { + size_t nCount(GetUndoManager().GetRedoActionCount()); + Sequence<OUString> aSeq(nCount); + auto aSeqRange = asNonConstRange(aSeq); + for (size_t n = 0; n < nCount; ++n) + aSeqRange[n] = GetUndoManager().GetRedoActionComment(n); + aReturn.aValue <<= aSeq; + aReturn.bEnabled = true; + break; + } + + default: + aReturn = OSingleDocumentController_Base::GetState(_nId); + } + return aReturn; + } + void OSingleDocumentController::Execute( sal_uInt16 _nId, const Sequence< PropertyValue >& _rArgs ) + { + switch ( _nId ) + { + case ID_BROWSER_UNDO: + case ID_BROWSER_REDO: + { + sal_Int16 nCount(1); + if (_rArgs.hasElements() && _rArgs[0].Name != "KeyModifier") + _rArgs[0].Value >>= nCount; + + while (nCount--) + { + if (_nId == ID_BROWSER_UNDO) + GetUndoManager().Undo(); + else + GetUndoManager().Redo(); + } + + InvalidateFeature( ID_BROWSER_UNDO ); + InvalidateFeature( ID_BROWSER_REDO ); + break; + } + + default: + OSingleDocumentController_Base::Execute( _nId, _rArgs ); + break; + } + InvalidateFeature(_nId); + } + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/misc/stringlistitem.cxx b/dbaccess/source/ui/misc/stringlistitem.cxx new file mode 100644 index 000000000..97e75fe6d --- /dev/null +++ b/dbaccess/source/ui/misc/stringlistitem.cxx @@ -0,0 +1,62 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <stringlistitem.hxx> + +namespace dbaui +{ +using namespace ::com::sun::star::uno; + +// OStringListItem +OStringListItem::OStringListItem(sal_Int16 _nWhich, const Sequence<OUString>& _rList) + : SfxPoolItem(_nWhich) + , m_aList(_rList) +{ +} + +OStringListItem::OStringListItem(const OStringListItem& _rSource) + : SfxPoolItem(_rSource) + , m_aList(_rSource.m_aList) +{ +} + +bool OStringListItem::operator==(const SfxPoolItem& _rItem) const +{ + if (!SfxPoolItem::operator==(_rItem)) + return false; + const OStringListItem* pCompare = static_cast<const OStringListItem*>(&_rItem); + if (pCompare->m_aList.getLength() != m_aList.getLength()) + return false; + + // compare all strings individually + for (sal_Int32 i = 0; i < m_aList.getLength(); ++i) + if (m_aList[i] != pCompare->m_aList[i]) + return false; + + return true; +} + +OStringListItem* OStringListItem::Clone(SfxItemPool* /* _pPool */) const +{ + return new OStringListItem(*this); +} + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |