android: Update app icon to new startcenter icon
[LibreOffice.git] / dbaccess / source / ui / dlg / DbAdminImpl.cxx
blob7e8aa1f0d1efd61ea28dc37e5d3ffdb3e1a5e2d9
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "DbAdminImpl.hxx"
21 #include <dsmeta.hxx>
23 #include <svl/poolitem.hxx>
24 #include <svl/itempool.hxx>
25 #include <svl/stritem.hxx>
26 #include <svl/intitem.hxx>
27 #include <svl/eitem.hxx>
28 #include <IItemSetHelper.hxx>
29 #include <UITools.hxx>
30 #include <core_resource.hxx>
31 #include <strings.hrc>
32 #include <strings.hxx>
33 #include <dsitems.hxx>
34 #include "dsnItem.hxx"
35 #include "optionalboolitem.hxx"
36 #include <stringlistitem.hxx>
37 #include <OAuthenticationContinuation.hxx>
39 #include <com/sun/star/beans/PropertyAttribute.hpp>
40 #include <com/sun/star/frame/XStorable.hpp>
41 #include <com/sun/star/sdb/DatabaseContext.hpp>
42 #include <com/sun/star/sdb/SQLContext.hpp>
43 #include <com/sun/star/sdbc/ConnectionPool.hpp>
44 #include <com/sun/star/sdbc/XDriver.hpp>
45 #include <com/sun/star/task/InteractionHandler.hpp>
46 #include <com/sun/star/ucb/AuthenticationRequest.hpp>
48 #include <comphelper/interaction.hxx>
49 #include <comphelper/sequence.hxx>
50 #include <connectivity/DriversConfig.hxx>
51 #include <connectivity/dbexception.hxx>
52 #include <osl/file.hxx>
53 #include <comphelper/diagnose_ex.hxx>
54 #include <osl/diagnose.h>
55 #include <sal/log.hxx>
56 #include <typelib/typedescription.hxx>
57 #include <vcl/svapp.hxx>
58 #include <vcl/stdtext.hxx>
59 #include <vcl/weld.hxx>
61 #include <algorithm>
62 #include <iterator>
63 #include <functional>
64 #include <o3tl/functional.hxx>
65 #include <comphelper/string.hxx>
67 namespace dbaui
69 using namespace ::dbtools;
70 using namespace com::sun::star::uno;
71 using namespace com::sun::star;
72 using namespace com::sun::star::ucb;
73 using namespace com::sun::star::task;
74 using namespace com::sun::star::sdbc;
75 using namespace com::sun::star::sdb;
76 using namespace com::sun::star::lang;
77 using namespace com::sun::star::beans;
78 using namespace com::sun::star::util;
79 using namespace com::sun::star::container;
80 using namespace com::sun::star::frame;
82 namespace
84 bool implCheckItemType( SfxItemSet const & _rSet, const sal_uInt16 _nId, const std::function<bool ( const SfxPoolItem* )>& isItemType )
86 bool bCorrectType = false;
88 SfxItemPool* pPool = _rSet.GetPool();
89 OSL_ENSURE( pPool, "implCheckItemType: invalid item pool!" );
90 if ( pPool )
92 const SfxPoolItem& rDefItem = pPool->GetDefaultItem( _nId );
93 bCorrectType = isItemType(&rDefItem);
95 return bCorrectType;
98 void lcl_putProperty(const Reference< XPropertySet >& _rxSet, const OUString& _rName, const Any& _rValue)
102 if ( _rxSet.is() )
103 _rxSet->setPropertyValue(_rName, _rValue);
105 catch(Exception&)
107 SAL_WARN("dbaccess", "ODbAdminDialog::implTranslateProperty: could not set the property "
108 << _rName);
113 OUString lcl_createHostWithPort(const SfxStringItem* _pHostName,const SfxInt32Item* _pPortNumber)
115 OUString sNewUrl;
117 if ( _pHostName && _pHostName->GetValue().getLength() )
118 sNewUrl = _pHostName->GetValue();
120 if ( _pPortNumber )
122 sNewUrl += ":" + OUString::number(_pPortNumber->GetValue());
125 return sNewUrl;
129 // ODbDataSourceAdministrationHelper
130 ODbDataSourceAdministrationHelper::ODbDataSourceAdministrationHelper(const Reference< XComponentContext >& _xORB, weld::Window* pParent, weld::Window* pTopParent, IItemSetHelper* _pItemSetHelper)
131 : m_xContext(_xORB)
132 , m_pParent(pParent)
133 , m_pItemSetHelper(_pItemSetHelper)
135 /// initialize the property translation map
136 // direct properties of a data source
137 m_aDirectPropTranslator.emplace( DSID_CONNECTURL, PROPERTY_URL );
138 m_aDirectPropTranslator.emplace( DSID_NAME, PROPERTY_NAME );
139 m_aDirectPropTranslator.emplace( DSID_USER, PROPERTY_USER );
140 m_aDirectPropTranslator.emplace( DSID_PASSWORD, PROPERTY_PASSWORD );
141 m_aDirectPropTranslator.emplace( DSID_PASSWORDREQUIRED, PROPERTY_ISPASSWORDREQUIRED );
142 m_aDirectPropTranslator.emplace( DSID_TABLEFILTER, PROPERTY_TABLEFILTER );
143 m_aDirectPropTranslator.emplace( DSID_READONLY, PROPERTY_ISREADONLY );
144 m_aDirectPropTranslator.emplace( DSID_SUPPRESSVERSIONCL, PROPERTY_SUPPRESSVERSIONCL );
146 // implicit properties, to be found in the direct property "Info"
147 m_aIndirectPropTranslator.emplace( DSID_JDBCDRIVERCLASS, INFO_JDBCDRIVERCLASS );
148 m_aIndirectPropTranslator.emplace( DSID_TEXTFILEEXTENSION, INFO_TEXTFILEEXTENSION );
149 m_aIndirectPropTranslator.emplace( DSID_CHARSET, INFO_CHARSET );
150 m_aIndirectPropTranslator.emplace( DSID_TEXTFILEHEADER, INFO_TEXTFILEHEADER );
151 m_aIndirectPropTranslator.emplace( DSID_FIELDDELIMITER, INFO_FIELDDELIMITER );
152 m_aIndirectPropTranslator.emplace( DSID_TEXTDELIMITER, INFO_TEXTDELIMITER );
153 m_aIndirectPropTranslator.emplace( DSID_DECIMALDELIMITER, INFO_DECIMALDELIMITER );
154 m_aIndirectPropTranslator.emplace( DSID_THOUSANDSDELIMITER, INFO_THOUSANDSDELIMITER );
155 m_aIndirectPropTranslator.emplace( DSID_SHOWDELETEDROWS, INFO_SHOWDELETEDROWS );
156 m_aIndirectPropTranslator.emplace( DSID_ALLOWLONGTABLENAMES, INFO_ALLOWLONGTABLENAMES );
157 m_aIndirectPropTranslator.emplace( DSID_ADDITIONALOPTIONS, INFO_ADDITIONALOPTIONS );
158 m_aIndirectPropTranslator.emplace( DSID_SQL92CHECK, PROPERTY_ENABLESQL92CHECK );
159 m_aIndirectPropTranslator.emplace( DSID_AUTOINCREMENTVALUE, PROPERTY_AUTOINCREMENTCREATION );
160 m_aIndirectPropTranslator.emplace( DSID_AUTORETRIEVEVALUE, INFO_AUTORETRIEVEVALUE );
161 m_aIndirectPropTranslator.emplace( DSID_AUTORETRIEVEENABLED, INFO_AUTORETRIEVEENABLED );
162 m_aIndirectPropTranslator.emplace( DSID_APPEND_TABLE_ALIAS, INFO_APPEND_TABLE_ALIAS );
163 m_aIndirectPropTranslator.emplace( DSID_AS_BEFORE_CORRNAME, INFO_AS_BEFORE_CORRELATION_NAME );
164 m_aIndirectPropTranslator.emplace( DSID_CHECK_REQUIRED_FIELDS, INFO_FORMS_CHECK_REQUIRED_FIELDS );
165 m_aIndirectPropTranslator.emplace( DSID_ESCAPE_DATETIME, INFO_ESCAPE_DATETIME );
166 m_aIndirectPropTranslator.emplace( DSID_PRIMARY_KEY_SUPPORT, OUString("PrimaryKeySupport") );
167 m_aIndirectPropTranslator.emplace( DSID_PARAMETERNAMESUBST, INFO_PARAMETERNAMESUBST );
168 m_aIndirectPropTranslator.emplace( DSID_IGNOREDRIVER_PRIV, INFO_IGNOREDRIVER_PRIV );
169 m_aIndirectPropTranslator.emplace( DSID_BOOLEANCOMPARISON, PROPERTY_BOOLEANCOMPARISONMODE );
170 m_aIndirectPropTranslator.emplace( DSID_ENABLEOUTERJOIN, PROPERTY_ENABLEOUTERJOIN );
171 m_aIndirectPropTranslator.emplace( DSID_CATALOG, PROPERTY_USECATALOGINSELECT );
172 m_aIndirectPropTranslator.emplace( DSID_SCHEMA, PROPERTY_USESCHEMAINSELECT );
173 m_aIndirectPropTranslator.emplace( DSID_INDEXAPPENDIX, OUString("AddIndexAppendix") );
174 m_aIndirectPropTranslator.emplace( DSID_DOSLINEENDS, OUString("PreferDosLikeLineEnds") );
175 m_aIndirectPropTranslator.emplace( DSID_CONN_SOCKET, OUString("LocalSocket") );
176 m_aIndirectPropTranslator.emplace( DSID_NAMED_PIPE, OUString("NamedPipe") );
177 m_aIndirectPropTranslator.emplace( DSID_RESPECTRESULTSETTYPE, OUString("RespectDriverResultSetType") );
178 m_aIndirectPropTranslator.emplace( DSID_MAX_ROW_SCAN, OUString("MaxRowScan") );
180 // extra settings for ODBC
181 m_aIndirectPropTranslator.emplace( DSID_USECATALOG, INFO_USECATALOG );
182 // extra settings for an LDAP address book
183 m_aIndirectPropTranslator.emplace( DSID_CONN_LDAP_BASEDN, INFO_CONN_LDAP_BASEDN );
184 m_aIndirectPropTranslator.emplace( DSID_CONN_LDAP_ROWCOUNT, INFO_CONN_LDAP_ROWCOUNT );
185 m_aIndirectPropTranslator.emplace( DSID_CONN_LDAP_USESSL, OUString("UseSSL") );
186 m_aIndirectPropTranslator.emplace( DSID_DOCUMENT_URL, PROPERTY_URL );
188 // Oracle
189 m_aIndirectPropTranslator.emplace( DSID_IGNORECURRENCY, OUString("IgnoreCurrency") );
193 m_xDatabaseContext = DatabaseContext::create(m_xContext);
195 catch(const Exception&)
197 ShowServiceNotAvailableError(pTopParent, u"com.sun.star.sdb.DatabaseContext", true);
201 bool ODbDataSourceAdministrationHelper::getCurrentSettings(Sequence< PropertyValue >& _rDriverParam)
203 OSL_ENSURE(m_pItemSetHelper->getOutputSet(), "ODbDataSourceAdministrationHelper::getCurrentSettings : not to be called without an example set!");
204 if (!m_pItemSetHelper->getOutputSet())
205 return false;
207 std::vector< PropertyValue > aReturn;
208 // collecting this in a vector because it has a push_back, in opposite to sequences
210 // user: DSID_USER -> "user"
211 const SfxStringItem* pUser = m_pItemSetHelper->getOutputSet()->GetItem<SfxStringItem>(DSID_USER);
212 if (pUser && pUser->GetValue().getLength())
213 aReturn.emplace_back( "user", 0,
214 Any(pUser->GetValue()), PropertyState_DIRECT_VALUE);
216 // check if the connection type requires a password
217 if (hasAuthentication(*m_pItemSetHelper->getOutputSet()))
219 // password: DSID_PASSWORD -> password
220 const SfxStringItem* pPassword = m_pItemSetHelper->getOutputSet()->GetItem<SfxStringItem>(DSID_PASSWORD);
221 OUString sPassword = pPassword ? pPassword->GetValue() : OUString();
222 const SfxBoolItem* pPasswordRequired = m_pItemSetHelper->getOutputSet()->GetItem<SfxBoolItem>(DSID_PASSWORDREQUIRED);
223 // if the set does not contain a password, but the item set says it requires one, ask the user
224 if ((!pPassword || !pPassword->GetValue().getLength()) && (pPasswordRequired && pPasswordRequired->GetValue()))
226 const SfxStringItem* pName = m_pItemSetHelper->getOutputSet()->GetItem<SfxStringItem>(DSID_NAME);
228 Reference< XModel > xModel( getDataSourceOrModel( m_xDatasource ), UNO_QUERY_THROW );
229 ::comphelper::NamedValueCollection aArgs( xModel->getArgs() );
230 Reference< XInteractionHandler > xHandler( aArgs.getOrDefault( "InteractionHandler", Reference< XInteractionHandler >() ) );
232 if ( !xHandler.is() )
234 // instantiate the default SDB interaction handler
235 xHandler = task::InteractionHandler::createWithParent(m_xContext, m_pParent->GetXWindow());
238 OUString sName = pName ? pName->GetValue() : OUString();
239 OUString sLoginRequest(DBA_RES(STR_ENTER_CONNECTION_PASSWORD));
240 OUString sTemp = sName;
241 sName = ::dbaui::getStrippedDatabaseName(nullptr,sTemp);
242 if ( !sName.isEmpty() )
243 sLoginRequest = sLoginRequest.replaceAll("$name$", sName);
244 else
246 sLoginRequest = sLoginRequest.replaceAll("\"$name$\"", "");
247 // ensure that in other languages the string will be deleted
248 sLoginRequest = sLoginRequest.replaceAll("$name$", "");
251 // the request
252 AuthenticationRequest aRequest;
253 aRequest.ServerName = sName;
254 aRequest.Diagnostic = sLoginRequest;
255 aRequest.HasRealm = false;
256 // aRequest.Realm
257 aRequest.HasUserName = pUser != nullptr;
258 aRequest.UserName = pUser ? pUser->GetValue() : OUString();
259 aRequest.HasPassword = true;
260 //aRequest.Password
261 aRequest.HasAccount = false;
262 // aRequest.Account
264 rtl::Reference<comphelper::OInteractionRequest> pRequest = new comphelper::OInteractionRequest(Any(aRequest));
266 // build an interaction request
267 // two continuations (Ok and Cancel)
268 ::rtl::Reference< comphelper::OInteractionAbort > pAbort = new comphelper::OInteractionAbort;
269 ::rtl::Reference< dbaccess::OAuthenticationContinuation > pAuthenticate = new dbaccess::OAuthenticationContinuation;
270 pAuthenticate->setCanChangeUserName( false );
271 pAuthenticate->setRememberPassword( RememberAuthentication_SESSION );
273 // some knittings
274 pRequest->addContinuation(pAbort);
275 pRequest->addContinuation(pAuthenticate);
277 // handle the request
280 SolarMutexGuard aSolarGuard;
281 // release the mutex when calling the handler, it may need to lock the SolarMutex
282 xHandler->handle(pRequest);
284 catch(Exception&)
286 DBG_UNHANDLED_EXCEPTION("dbaccess");
288 if (!pAuthenticate->wasSelected())
289 return false;
291 sPassword = pAuthenticate->getPassword();
292 if (pAuthenticate->getRememberPassword())
293 m_pItemSetHelper->getWriteOutputSet()->Put(SfxStringItem(DSID_PASSWORD, sPassword));
296 if (!sPassword.isEmpty())
297 aReturn.emplace_back( "password", 0,
298 Any(sPassword), PropertyState_DIRECT_VALUE);
301 if ( !aReturn.empty() )
302 _rDriverParam = comphelper::containerToSequence(aReturn);
304 // append all the other stuff (charset etc.)
305 fillDatasourceInfo(*m_pItemSetHelper->getOutputSet(), _rDriverParam);
307 return true;
310 void ODbDataSourceAdministrationHelper::successfullyConnected()
312 OSL_ENSURE(m_pItemSetHelper->getOutputSet(), "ODbDataSourceAdministrationHelper::successfullyConnected: not to be called without an example set!");
313 if (!m_pItemSetHelper->getOutputSet())
314 return;
316 if (hasAuthentication(*m_pItemSetHelper->getOutputSet()))
318 const SfxStringItem* pPassword = m_pItemSetHelper->getOutputSet()->GetItem<SfxStringItem>(DSID_PASSWORD);
319 if (pPassword && (0 != pPassword->GetValue().getLength()))
321 OUString sPassword = pPassword->GetValue();
323 Reference< XPropertySet > xCurrentDatasource = getCurrentDataSource();
324 lcl_putProperty(xCurrentDatasource,m_aDirectPropTranslator[DSID_PASSWORD], Any(sPassword));
329 void ODbDataSourceAdministrationHelper::clearPassword()
331 if (m_pItemSetHelper->getWriteOutputSet())
332 m_pItemSetHelper->getWriteOutputSet()->ClearItem(DSID_PASSWORD);
335 std::pair< Reference<XConnection>,bool> ODbDataSourceAdministrationHelper::createConnection()
337 std::pair< Reference<XConnection>,bool> aRet;
338 aRet.second = false;
339 Sequence< PropertyValue > aConnectionParams;
340 if ( getCurrentSettings(aConnectionParams) )
342 // the current DSN
343 // fill the table list with this connection information
344 SQLExceptionInfo aErrorInfo;
347 weld::WaitObject aWaitCursor(m_pParent);
348 aRet.first = getDriver()->connect(getConnectionURL(), aConnectionParams);
349 aRet.second = true;
351 catch (const SQLContext& e) { aErrorInfo = SQLExceptionInfo(e); }
352 catch (const SQLWarning& e) { aErrorInfo = SQLExceptionInfo(e); }
353 catch (const SQLException& e) { aErrorInfo = SQLExceptionInfo(e); }
355 showError(aErrorInfo,m_pParent->GetXWindow(),getORB());
357 if ( aRet.first.is() )
358 successfullyConnected();// notify the admindlg to save the password
360 return aRet;
363 Reference< XDriver > ODbDataSourceAdministrationHelper::getDriver()
365 return getDriver(getConnectionURL());
368 Reference< XDriver > ODbDataSourceAdministrationHelper::getDriver(const OUString& _sURL)
370 // get the global DriverManager
371 Reference< XConnectionPool > xDriverManager;
373 OUString sCurrentActionError = DBA_RES(STR_COULDNOTCREATE_DRIVERMANAGER);
374 sCurrentActionError = sCurrentActionError.replaceFirst("#servicename#", "com.sun.star.sdbc.ConnectionPool");
378 xDriverManager.set( ConnectionPool::create( getORB() ) );
380 catch (const Exception&)
382 css::uno::Any anyEx = cppu::getCaughtException();
383 // wrap the exception into an SQLException
384 throw SQLException(sCurrentActionError, getORB(), "S1000", 0, anyEx);
387 Reference< XDriver > xDriver = xDriverManager->getDriverByURL(_sURL);
388 if (!xDriver.is())
390 sCurrentActionError = DBA_RES(STR_NOREGISTEREDDRIVER);
391 sCurrentActionError = sCurrentActionError.replaceFirst("#connurl#", _sURL);
392 // will be caught and translated into an SQLContext exception
393 throw SQLException(sCurrentActionError, getORB(), "S1000", 0, Any());
395 return xDriver;
398 Reference< XPropertySet > const & ODbDataSourceAdministrationHelper::getCurrentDataSource()
400 if ( !m_xDatasource.is() )
402 Reference<XInterface> xIn(m_aDataSourceOrName,UNO_QUERY);
403 if ( !xIn.is() )
405 OUString sCurrentDatasource;
406 m_aDataSourceOrName >>= sCurrentDatasource;
407 OSL_ENSURE(!sCurrentDatasource.isEmpty(),"No datasource name given!");
410 if ( m_xDatabaseContext.is() )
411 m_xDatasource.set(m_xDatabaseContext->getByName(sCurrentDatasource),UNO_QUERY);
412 xIn = m_xDatasource;
414 catch(const Exception&)
418 m_xModel.set(getDataSourceOrModel(xIn),UNO_QUERY);
419 if ( m_xModel.is() )
420 m_xDatasource.set(xIn,UNO_QUERY);
421 else
423 m_xDatasource.set(getDataSourceOrModel(xIn),UNO_QUERY);
424 m_xModel.set(xIn,UNO_QUERY);
428 OSL_ENSURE(m_xDatasource.is(), "ODbDataSourceAdministrationHelper::getCurrentDataSource: no data source!");
429 return m_xDatasource;
432 OUString ODbDataSourceAdministrationHelper::getDatasourceType( const SfxItemSet& _rSet )
434 const SfxStringItem* pConnectURL = _rSet.GetItem<SfxStringItem>(DSID_CONNECTURL);
435 OSL_ENSURE( pConnectURL , "ODbDataSourceAdministrationHelper::getDatasourceType: invalid items in the source set!" );
436 const DbuTypeCollectionItem* pTypeCollection = _rSet.GetItem<DbuTypeCollectionItem>(DSID_TYPECOLLECTION);
437 OSL_ENSURE(pTypeCollection, "ODbDataSourceAdministrationHelper::getDatasourceType: invalid items in the source set!");
438 ::dbaccess::ODsnTypeCollection* pCollection = pTypeCollection->getCollection();
439 return pCollection->getType(pConnectURL->GetValue());
442 bool ODbDataSourceAdministrationHelper::hasAuthentication(const SfxItemSet& _rSet)
444 return DataSourceMetaData::getAuthentication( getDatasourceType( _rSet ) ) != AuthNone;
447 OUString ODbDataSourceAdministrationHelper::getConnectionURL() const
449 OUString sNewUrl;
451 OUString eType = getDatasourceType(*m_pItemSetHelper->getOutputSet());
453 const SfxStringItem* pUrlItem = m_pItemSetHelper->getOutputSet()->GetItem<SfxStringItem>(DSID_CONNECTURL);
454 const DbuTypeCollectionItem* pTypeCollection = m_pItemSetHelper->getOutputSet()->GetItem<DbuTypeCollectionItem>(DSID_TYPECOLLECTION);
456 OSL_ENSURE(pUrlItem,"Connection URL is NULL. -> GPF!");
457 OSL_ENSURE(pTypeCollection, "ODbDataSourceAdministrationHelper::getDatasourceType: invalid items in the source set!");
458 ::dbaccess::ODsnTypeCollection* pCollection = pTypeCollection->getCollection();
459 OSL_ENSURE(pCollection, "ODbDataSourceAdministrationHelper::getDatasourceType: invalid type collection!");
461 switch( pCollection->determineType(eType) )
463 case ::dbaccess::DST_DBASE:
464 case ::dbaccess::DST_FLAT:
465 case ::dbaccess::DST_CALC:
466 case ::dbaccess::DST_WRITER:
467 break;
468 case ::dbaccess::DST_MSACCESS:
469 case ::dbaccess::DST_MSACCESS_2007:
471 OUString sFileName = pCollection->cutPrefix(pUrlItem->GetValue());
472 OUString sNewFileName;
473 if ( ::osl::FileBase::getSystemPathFromFileURL( sFileName, sNewFileName ) == ::osl::FileBase::E_None )
475 sNewUrl += sNewFileName;
478 break;
479 case ::dbaccess::DST_MYSQL_NATIVE:
480 case ::dbaccess::DST_MYSQL_JDBC:
482 const SfxStringItem* pHostName = m_pItemSetHelper->getOutputSet()->GetItem<SfxStringItem>(DSID_CONN_HOSTNAME);
483 const SfxInt32Item* pPortNumber = m_pItemSetHelper->getOutputSet()->GetItem<SfxInt32Item>(DSID_MYSQL_PORTNUMBER);
484 const SfxStringItem* pDatabaseName = m_pItemSetHelper->getOutputSet()->GetItem<SfxStringItem>(DSID_DATABASENAME);
485 sNewUrl = lcl_createHostWithPort(pHostName,pPortNumber);
486 OUString sDatabaseName = pDatabaseName ? pDatabaseName->GetValue() : OUString();
487 if ( !sDatabaseName.getLength() && pUrlItem )
488 sDatabaseName = pCollection->cutPrefix( pUrlItem->GetValue() );
489 // TODO: what's that? Why is the database name transported via the URL Item?
490 // Huh? Anybody there?
491 // OJ: It is needed when the connection properties are changed. There the URL is used for every type.
493 if ( !sDatabaseName.isEmpty() )
495 sNewUrl += "/" + sDatabaseName;
498 break;
499 case ::dbaccess::DST_ORACLE_JDBC:
501 const SfxStringItem* pHostName = m_pItemSetHelper->getOutputSet()->GetItem<SfxStringItem>(DSID_CONN_HOSTNAME);
502 const SfxInt32Item* pPortNumber = m_pItemSetHelper->getOutputSet()->GetItem<SfxInt32Item>(DSID_ORACLE_PORTNUMBER);
503 const SfxStringItem* pDatabaseName = m_pItemSetHelper->getOutputSet()->GetItem<SfxStringItem>(DSID_DATABASENAME);
504 if ( pHostName && pHostName->GetValue().getLength() )
506 sNewUrl = "@" + lcl_createHostWithPort(pHostName,pPortNumber);
507 OUString sDatabaseName = pDatabaseName ? pDatabaseName->GetValue() : OUString();
508 if ( sDatabaseName.isEmpty() && pUrlItem )
509 sDatabaseName = pCollection->cutPrefix( pUrlItem->GetValue() );
510 if ( !sDatabaseName.isEmpty() )
512 sNewUrl += ":" + sDatabaseName;
515 else
516 { // here someone entered a JDBC url which looks like oracle, so we have to use the url property
520 break;
521 case ::dbaccess::DST_LDAP:
523 const SfxInt32Item* pPortNumber = m_pItemSetHelper->getOutputSet()->GetItem<SfxInt32Item>(DSID_CONN_LDAP_PORTNUMBER);
524 sNewUrl = pCollection->cutPrefix(pUrlItem->GetValue()) + lcl_createHostWithPort(nullptr,pPortNumber);
526 break;
527 case ::dbaccess::DST_POSTGRES:
529 sNewUrl = pCollection->cutPrefix(pUrlItem->GetValue());
530 OUString rURL(comphelper::string::stripEnd(pUrlItem->GetValue(), '*'));
531 const SfxStringItem* pHostName = m_pItemSetHelper->getOutputSet()->GetItem<SfxStringItem>(DSID_CONN_HOSTNAME);
532 const SfxInt32Item* pPortNumber = m_pItemSetHelper->getOutputSet()->GetItem<SfxInt32Item>(DSID_POSTGRES_PORTNUMBER);
533 const SfxStringItem* pDatabaseName = m_pItemSetHelper->getOutputSet()->GetItem<SfxStringItem>(DSID_DATABASENAME);
534 if (pHostName && pHostName->GetValue().getLength())
536 OUString hostname( pHostName->GetValue() );
537 hostname = hostname.replaceAll( "\\", "\\\\");
538 hostname = hostname.replaceAll( "\'", "\\'");
539 hostname = "'" + hostname + "'";
540 rURL += " host=" + hostname;
542 // tdf#157260: if port is already in the URL, don't add another one
543 if (pPortNumber && pPortNumber->GetValue() && (rURL.indexOf("port=") == -1))
545 OUString port = "'" + OUString::number(pPortNumber->GetValue()) + "'";
546 rURL += " port=" + port;
548 if (pDatabaseName && pDatabaseName->GetValue().getLength())
550 OUString dbname( pDatabaseName->GetValue() );
551 dbname = dbname.replaceAll( "\\", "\\\\");
552 dbname = dbname.replaceAll( "\'", "\\'");
553 dbname = "'" + dbname + "'";
554 rURL += " dbname=" + dbname;
556 sNewUrl = rURL;
557 return sNewUrl;
559 break;
560 case ::dbaccess::DST_JDBC:
561 // run through
562 default:
563 break;
565 if ( !sNewUrl.isEmpty() )
566 sNewUrl = pCollection->getPrefix(eType) + sNewUrl;
567 else if (pUrlItem)
568 sNewUrl = pUrlItem->GetValue();
570 return sNewUrl;
573 namespace {
575 struct PropertyValueLess
577 bool operator() (const PropertyValue& x, const PropertyValue& y) const
578 { return x.Name < y.Name; } // construct prevents a MSVC6 warning
583 typedef std::set<PropertyValue, PropertyValueLess> PropertyValueSet;
585 void ODbDataSourceAdministrationHelper::translateProperties(const Reference< XPropertySet >& _rxSource, SfxItemSet& _rDest)
587 if (_rxSource.is())
589 for (auto const& elem : m_aDirectPropTranslator)
591 // get the property value
592 Any aValue;
595 aValue = _rxSource->getPropertyValue(elem.second);
597 catch(Exception&)
599 SAL_WARN("dbaccess", "ODbDataSourceAdministrationHelper::translateProperties: could not extract the property "
600 << elem.second);
602 // transfer it into an item
603 implTranslateProperty(_rDest, elem.first, aValue);
606 // get the additional information
607 Sequence< PropertyValue > aAdditionalInfo;
610 _rxSource->getPropertyValue(PROPERTY_INFO) >>= aAdditionalInfo;
612 catch(Exception&) { }
614 // collect the names of the additional settings
615 PropertyValueSet aInfos;
616 for (const PropertyValue& rAdditionalInfo : std::as_const(aAdditionalInfo))
618 if( rAdditionalInfo.Name == "JDBCDRV" )
619 { // compatibility
620 PropertyValue aCompatibility(rAdditionalInfo);
621 aCompatibility.Name = "JavaDriverClass";
622 aInfos.insert(aCompatibility);
624 else
625 aInfos.insert(rAdditionalInfo);
628 // go through all known translations and check if we have such a setting
629 if ( !aInfos.empty() )
631 PropertyValue aSearchFor;
632 for (auto const& elem : m_aIndirectPropTranslator)
634 aSearchFor.Name = elem.second;
635 PropertyValueSet::const_iterator aInfoPos = aInfos.find(aSearchFor);
636 if (aInfos.end() != aInfoPos)
637 // the property is contained in the info sequence
638 // -> transfer it into an item
639 implTranslateProperty(_rDest, elem.first, aInfoPos->Value);
643 convertUrl(_rDest);
648 Reference<XStorable> xStore(getDataSourceOrModel(_rxSource),UNO_QUERY);
649 _rDest.Put(SfxBoolItem(DSID_READONLY, !xStore.is() || xStore->isReadonly() ));
651 catch(Exception&)
653 TOOLS_WARN_EXCEPTION("dbaccess", "IsReadOnly throws");
657 void ODbDataSourceAdministrationHelper::translateProperties(const SfxItemSet& _rSource, const Reference< XPropertySet >& _rxDest)
659 OSL_ENSURE(_rxDest.is(), "ODbDataSourceAdministrationHelper::translateProperties: invalid property set!");
660 if (!_rxDest.is())
661 return;
663 // the property set info
664 Reference< XPropertySetInfo > xInfo;
665 try { xInfo = _rxDest->getPropertySetInfo(); }
666 catch(Exception&) { }
668 static const OUStringLiteral sUrlProp(u"URL");
669 // transfer the direct properties
670 for (auto const& elem : m_aDirectPropTranslator)
672 const SfxPoolItem* pCurrentItem = _rSource.GetItem(static_cast<sal_uInt16>(elem.first));
673 if (pCurrentItem)
675 sal_Int16 nAttributes = PropertyAttribute::READONLY;
676 if (xInfo.is())
678 try { nAttributes = xInfo->getPropertyByName(elem.second).Attributes; }
679 catch(Exception&) { }
681 if ((nAttributes & PropertyAttribute::READONLY) == 0)
683 if ( sUrlProp == elem.second )
685 Any aValue(getConnectionURL());
686 // aValue <<= OUString();
687 lcl_putProperty(_rxDest, elem.second,aValue);
689 else
690 implTranslateProperty(_rxDest, elem.second, pCurrentItem);
695 // now for the indirect properties
697 Sequence< PropertyValue > aInfo;
698 // the original properties
701 _rxDest->getPropertyValue(PROPERTY_INFO) >>= aInfo;
703 catch(Exception&) { }
705 // overwrite and extend them
706 fillDatasourceInfo(_rSource, aInfo);
707 // and propagate the (newly composed) sequence to the set
708 lcl_putProperty(_rxDest,PROPERTY_INFO, Any(aInfo));
711 void ODbDataSourceAdministrationHelper::fillDatasourceInfo(const SfxItemSet& _rSource, Sequence< css::beans::PropertyValue >& _rInfo)
713 // within the current "Info" sequence, replace the ones we can examine from the item set
714 // (we don't just fill a completely new sequence with our own items, but we preserve any properties unknown to
715 // us)
717 // first determine which of all the items are relevant for the data source (depends on the connection url)
718 const OUString eType = getDatasourceType(_rSource);
719 const ::connectivity::DriversConfig aDriverConfig(getORB());
720 const ::comphelper::NamedValueCollection& aProperties = aDriverConfig.getProperties(eType);
722 // collect the translated property values for the relevant items
723 PropertyValueSet aRelevantSettings;
724 MapInt2String::const_iterator aTranslation;
725 for (ItemID detailId = DSID_FIRST_ITEM_ID ; detailId <= DSID_LAST_ITEM_ID; ++detailId)
727 const SfxPoolItem* pCurrent = _rSource.GetItem(static_cast<sal_uInt16>(detailId));
728 aTranslation = m_aIndirectPropTranslator.find(detailId);
729 if ( pCurrent && (m_aIndirectPropTranslator.end() != aTranslation) &&
730 aProperties.has(aTranslation->second) )
732 if ( aTranslation->second == INFO_CHARSET )
734 OUString sCharSet;
735 implTranslateProperty(pCurrent) >>= sCharSet;
736 if ( !sCharSet.isEmpty() )
737 aRelevantSettings.insert(PropertyValue(aTranslation->second, 0, Any(sCharSet), PropertyState_DIRECT_VALUE));
739 else
740 aRelevantSettings.insert(PropertyValue(aTranslation->second, 0, implTranslateProperty(pCurrent), PropertyState_DIRECT_VALUE));
744 // settings to preserve
745 MapInt2String aPreservedSettings;
747 // now aRelevantSettings contains all the property values relevant for the current data source type,
748 // check the original sequence if it already contains any of these values (which have to be overwritten, then)
749 PropertyValue* pInfo = _rInfo.getArray();
750 PropertyValue aSearchFor;
751 sal_Int32 nObsoleteSetting = -1;
752 sal_Int32 nCount = _rInfo.getLength();
753 for (sal_Int32 i = 0; i < nCount; ++i, ++pInfo)
755 aSearchFor.Name = pInfo->Name;
756 PropertyValueSet::const_iterator aOverwrittenSetting = aRelevantSettings.find(aSearchFor);
757 if (aRelevantSettings.end() != aOverwrittenSetting)
758 { // the setting was present in the original sequence, and it is to be overwritten -> replace it
759 if ( pInfo->Value != aOverwrittenSetting->Value )
760 *pInfo = *aOverwrittenSetting;
761 aRelevantSettings.erase(aOverwrittenSetting);
763 else if( pInfo->Name == "JDBCDRV" )
764 { // this is a compatibility setting, remove it from the sequence (it's replaced by JavaDriverClass)
765 nObsoleteSetting = i;
767 else
768 aPreservedSettings[i] = pInfo->Name;
770 if (-1 != nObsoleteSetting)
771 ::comphelper::removeElementAt(_rInfo, nObsoleteSetting);
773 if ( !aPreservedSettings.empty() )
774 { // check if there are settings which
775 // * are known as indirect properties
776 // * but not relevant for the current data source type
777 // These settings have to be removed: If they're not relevant, we have no UI for changing them.
779 // for this, we need a string-controlled quick access to m_aIndirectPropTranslator
780 std::set<OUString> aIndirectProps;
781 std::transform(m_aIndirectPropTranslator.begin(),
782 m_aIndirectPropTranslator.end(),
783 std::inserter(aIndirectProps,aIndirectProps.begin()),
784 ::o3tl::select2nd< MapInt2String::value_type >());
786 // now check the to-be-preserved props
787 std::vector< sal_Int32 > aRemoveIndexes;
788 sal_Int32 nPositionCorrector = 0;
789 for (auto const& preservedSetting : aPreservedSettings)
791 if (aIndirectProps.end() != aIndirectProps.find(preservedSetting.second))
793 aRemoveIndexes.push_back(preservedSetting.first - nPositionCorrector);
794 ++nPositionCorrector;
797 // now finally remove all such props
798 for (auto const& removeIndex : aRemoveIndexes)
799 ::comphelper::removeElementAt(_rInfo, removeIndex);
802 Sequence< Any> aTypeSettings;
803 aTypeSettings = aProperties.getOrDefault("TypeInfoSettings",aTypeSettings);
804 // here we have a special entry for types from oracle
805 if ( aTypeSettings.hasElements() )
807 aRelevantSettings.insert(PropertyValue("TypeInfoSettings", 0, Any(aTypeSettings), PropertyState_DIRECT_VALUE));
810 // check which values are still left ('cause they were not present in the original sequence, but are to be set)
811 if ( aRelevantSettings.empty() )
812 return;
814 sal_Int32 nOldLength = _rInfo.getLength();
815 _rInfo.realloc(nOldLength + aRelevantSettings.size());
816 PropertyValue* pAppendValues = _rInfo.getArray() + nOldLength;
817 for (auto const& relevantSetting : aRelevantSettings)
819 if ( relevantSetting.Name == INFO_CHARSET )
821 OUString sCharSet;
822 relevantSetting.Value >>= sCharSet;
823 if ( !sCharSet.isEmpty() )
824 *pAppendValues = relevantSetting;
826 else
827 *pAppendValues = relevantSetting;
828 ++pAppendValues;
832 Any ODbDataSourceAdministrationHelper::implTranslateProperty(const SfxPoolItem* _pItem)
834 // translate the SfxPoolItem
835 Any aValue;
837 const SfxStringItem* pStringItem = dynamic_cast<const SfxStringItem*>( _pItem );
838 const SfxBoolItem* pBoolItem = dynamic_cast<const SfxBoolItem*>( _pItem );
839 const OptionalBoolItem* pOptBoolItem = dynamic_cast<const OptionalBoolItem*>( _pItem );
840 const SfxInt32Item* pInt32Item = dynamic_cast< const SfxInt32Item* >( _pItem );
841 const OStringListItem* pStringListItem = dynamic_cast<const OStringListItem*>( _pItem );
843 if ( pStringItem )
845 aValue <<= pStringItem->GetValue();
847 else if ( pBoolItem )
849 aValue <<= pBoolItem->GetValue();
851 else if ( pOptBoolItem )
853 if ( !pOptBoolItem->HasValue() )
854 aValue.clear();
855 else
856 aValue <<= pOptBoolItem->GetValue();
858 else if ( pInt32Item )
860 aValue <<= pInt32Item->GetValue();
862 else if ( pStringListItem )
864 aValue <<= pStringListItem->getList();
866 else
868 OSL_FAIL("ODbDataSourceAdministrationHelper::implTranslateProperty: unsupported item type!");
869 return aValue;
872 return aValue;
875 void ODbDataSourceAdministrationHelper::implTranslateProperty(const Reference< XPropertySet >& _rxSet, const OUString& _rName, const SfxPoolItem* _pItem)
877 Any aValue = implTranslateProperty(_pItem);
878 lcl_putProperty(_rxSet, _rName,aValue);
881 OString ODbDataSourceAdministrationHelper::translatePropertyId( sal_Int32 _nId )
883 OUString aString;
885 MapInt2String::const_iterator aPos = m_aDirectPropTranslator.find( _nId );
886 if ( m_aDirectPropTranslator.end() != aPos )
888 aString = aPos->second;
890 else
892 MapInt2String::const_iterator indirectPos = m_aIndirectPropTranslator.find( _nId );
893 if ( m_aIndirectPropTranslator.end() != indirectPos )
894 aString = indirectPos->second;
897 return OUStringToOString( aString, RTL_TEXTENCODING_ASCII_US );
899 template<class T> static bool checkItemType(const SfxPoolItem* pItem){ return dynamic_cast<const T*>(pItem) != nullptr;}
901 void ODbDataSourceAdministrationHelper::implTranslateProperty( SfxItemSet& _rSet, sal_Int32 _nId, const Any& _rValue )
903 switch ( _rValue.getValueType().getTypeClass() )
905 case TypeClass_STRING:
906 if ( implCheckItemType( _rSet, _nId, checkItemType<SfxStringItem> ) )
908 OUString sValue;
909 _rValue >>= sValue;
910 _rSet.Put(SfxStringItem(_nId, sValue));
912 else {
913 SAL_WARN( "dbaccess", "ODbDataSourceAdministrationHelper::implTranslateProperty: invalid property value ("
914 << translatePropertyId(_nId) << " should be no string)!");
916 break;
918 case TypeClass_BOOLEAN:
919 if ( implCheckItemType( _rSet, _nId, checkItemType<SfxBoolItem> ) )
921 bool bVal = false;
922 _rValue >>= bVal;
923 _rSet.Put(SfxBoolItem(_nId, bVal));
925 else if ( implCheckItemType( _rSet, _nId, checkItemType<OptionalBoolItem> ) )
927 OptionalBoolItem aItem( _nId );
928 if ( _rValue.hasValue() )
930 bool bValue = false;
931 _rValue >>= bValue;
932 aItem.SetValue( bValue );
934 else
935 aItem.ClearValue();
936 _rSet.Put( aItem );
938 else {
939 SAL_WARN( "dbaccess", "ODbDataSourceAdministrationHelper::implTranslateProperty: invalid property value ("
940 << translatePropertyId(_nId)
941 << " should be no boolean)!");
943 break;
945 case TypeClass_LONG:
946 if ( implCheckItemType( _rSet, _nId, checkItemType<SfxInt32Item> ) )
948 sal_Int32 nValue = 0;
949 _rValue >>= nValue;
950 _rSet.Put( SfxInt32Item( TypedWhichId<SfxInt32Item>(_nId), nValue ) );
952 else {
953 SAL_WARN( "dbaccess", "ODbDataSourceAdministrationHelper::implTranslateProperty: invalid property value ("
954 << translatePropertyId(_nId)
955 << " should be no int)!");
957 break;
959 case TypeClass_SEQUENCE:
960 if ( implCheckItemType( _rSet, _nId, checkItemType<OStringListItem> ) )
962 // determine the element type
963 TypeDescription aTD(_rValue.getValueType());
964 typelib_IndirectTypeDescription* pSequenceTD =
965 reinterpret_cast< typelib_IndirectTypeDescription* >(aTD.get());
966 OSL_ENSURE(pSequenceTD && pSequenceTD->pType, "ODbDataSourceAdministrationHelper::implTranslateProperty: invalid sequence type!");
968 Type aElementType(pSequenceTD->pType);
969 switch (aElementType.getTypeClass())
971 case TypeClass_STRING:
973 Sequence< OUString > aStringList;
974 _rValue >>= aStringList;
975 _rSet.Put(OStringListItem(_nId, aStringList));
977 break;
978 default:
979 OSL_FAIL("ODbDataSourceAdministrationHelper::implTranslateProperty: unsupported property value type!");
982 else {
983 SAL_WARN( "dbaccess", "ODbDataSourceAdministrationHelper::implTranslateProperty: invalid property value ("
984 << translatePropertyId(_nId)
985 << " should be no string sequence)!");
987 break;
989 case TypeClass_VOID:
990 _rSet.ClearItem(_nId);
991 break;
993 default:
994 OSL_FAIL("ODbDataSourceAdministrationHelper::implTranslateProperty: unsupported property value type!");
998 OUString ODbDataSourceAdministrationHelper::getDocumentUrl(SfxItemSet const & _rDest)
1000 const SfxStringItem* pUrlItem = _rDest.GetItem<SfxStringItem>(DSID_DOCUMENT_URL);
1001 OSL_ENSURE(pUrlItem,"Document URL is NULL. -> GPF!");
1002 return pUrlItem->GetValue();
1005 void ODbDataSourceAdministrationHelper::convertUrl(SfxItemSet& _rDest)
1007 OUString eType = getDatasourceType(_rDest);
1009 const SfxStringItem* pUrlItem = _rDest.GetItem<SfxStringItem>(DSID_CONNECTURL);
1010 const DbuTypeCollectionItem* pTypeCollection = _rDest.GetItem<DbuTypeCollectionItem>(DSID_TYPECOLLECTION);
1012 OSL_ENSURE(pUrlItem,"Connection URL is NULL. -> GPF!");
1013 OSL_ENSURE(pTypeCollection, "ODbAdminDialog::getDatasourceType: invalid items in the source set!");
1014 ::dbaccess::ODsnTypeCollection* pCollection = pTypeCollection->getCollection();
1015 OSL_ENSURE(pCollection, "ODbAdminDialog::getDatasourceType: invalid type collection!");
1017 TypedWhichId<SfxInt32Item> nPortNumberId(0);
1018 sal_Int32 nPortNumber = -1;
1019 OUString sNewHostName;
1020 OUString sUrlPart;
1022 pCollection->extractHostNamePort(pUrlItem->GetValue(),sUrlPart,sNewHostName,nPortNumber);
1023 const ::dbaccess::DATASOURCE_TYPE eTy = pCollection->determineType(eType);
1025 switch( eTy )
1027 case ::dbaccess::DST_MYSQL_NATIVE:
1028 case ::dbaccess::DST_MYSQL_JDBC:
1029 nPortNumberId = DSID_MYSQL_PORTNUMBER;
1030 break;
1031 case ::dbaccess::DST_ORACLE_JDBC:
1032 nPortNumberId = DSID_ORACLE_PORTNUMBER;
1033 break;
1034 case ::dbaccess::DST_LDAP:
1035 nPortNumberId = DSID_CONN_LDAP_PORTNUMBER;
1036 break;
1037 case ::dbaccess::DST_POSTGRES:
1038 nPortNumberId = DSID_POSTGRES_PORTNUMBER;
1039 break;
1040 default:
1041 break;
1044 if ( !sUrlPart.isEmpty() )
1046 if ( eTy == ::dbaccess::DST_MYSQL_NATIVE )
1048 _rDest.Put( SfxStringItem( DSID_DATABASENAME, sUrlPart ) );
1050 else
1052 OUString sNewUrl = pCollection->getPrefix(eType) + sUrlPart;
1053 _rDest.Put( SfxStringItem( DSID_CONNECTURL, sNewUrl ) );
1057 if ( !sNewHostName.isEmpty() )
1058 _rDest.Put(SfxStringItem(DSID_CONN_HOSTNAME, sNewHostName));
1060 if ( nPortNumber != -1 && nPortNumberId != TypedWhichId<SfxInt32Item>(0) )
1061 _rDest.Put(SfxInt32Item(nPortNumberId, nPortNumber));
1065 bool ODbDataSourceAdministrationHelper::saveChanges(const SfxItemSet& _rSource)
1067 // put the remembered settings into the property set
1068 Reference<XPropertySet> xDatasource = getCurrentDataSource();
1069 if ( !xDatasource.is() )
1070 return false;
1072 translateProperties(_rSource,xDatasource );
1074 return true;
1077 void ODbDataSourceAdministrationHelper::setDataSourceOrName( const Any& _rDataSourceOrName )
1079 OSL_ENSURE( !m_aDataSourceOrName.hasValue(), "ODbDataSourceAdministrationHelper::setDataSourceOrName: already have one!" );
1080 // hmm. We could reset m_xDatasource/m_xModel, probably, and continue working
1081 m_aDataSourceOrName = _rDataSourceOrName;
1084 // DbuTypeCollectionItem
1085 DbuTypeCollectionItem::DbuTypeCollectionItem(sal_Int16 _nWhich, ::dbaccess::ODsnTypeCollection* _pCollection)
1086 :SfxPoolItem(_nWhich)
1087 ,m_pCollection(_pCollection)
1091 DbuTypeCollectionItem::DbuTypeCollectionItem(const DbuTypeCollectionItem& _rSource)
1092 :SfxPoolItem(_rSource)
1093 ,m_pCollection(_rSource.getCollection())
1097 bool DbuTypeCollectionItem::operator==(const SfxPoolItem& _rItem) const
1099 return SfxPoolItem::operator==(_rItem) &&
1100 static_cast<const DbuTypeCollectionItem&>( _rItem ).getCollection() == getCollection();
1103 DbuTypeCollectionItem* DbuTypeCollectionItem::Clone(SfxItemPool* /*_pPool*/) const
1105 return new DbuTypeCollectionItem(*this);
1108 } // namespace dbaui
1110 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */