diff options
Diffstat (limited to 'dbaccess/source/ui/misc/UITools.cxx')
-rw-r--r-- | dbaccess/source/ui/misc/UITools.cxx | 1370 |
1 files changed, 1370 insertions, 0 deletions
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: */ |