1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 .
21 #include <strings.hrc>
22 #include "abptypes.hxx"
23 #include <componentmodule.hxx>
24 #include "datasourcehandling.hxx"
25 #include "addresssettings.hxx"
27 #include <com/sun/star/beans/XPropertySet.hpp>
28 #include <com/sun/star/container/XNameAccess.hpp>
29 #include <com/sun/star/frame/XModel.hpp>
30 #include <com/sun/star/frame/XStorable.hpp>
31 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
32 #include <com/sun/star/sdb/DatabaseContext.hpp>
33 #include <com/sun/star/sdb/SQLContext.hpp>
34 #include <com/sun/star/sdb/XCompletedConnection.hpp>
35 #include <com/sun/star/sdb/XDatabaseRegistrations.hpp>
36 #include <com/sun/star/sdb/XDocumentDataSource.hpp>
37 #include <com/sun/star/sdbc/XConnection.hpp>
38 #include <com/sun/star/sdbcx/XTablesSupplier.hpp>
39 #include <com/sun/star/task/InteractionHandler.hpp>
40 #include <com/sun/star/uri/UriReferenceFactory.hpp>
41 #include <com/sun/star/uri/VndSunStarPkgUrlReferenceFactory.hpp>
43 #include <comphelper/interaction.hxx>
44 #include <comphelper/processfactory.hxx>
45 #include <tools/debug.hxx>
46 #include <comphelper/diagnose_ex.hxx>
47 #include <unotools/sharedunocomponent.hxx>
48 #include <vcl/stdtext.hxx>
49 #include <vcl/weld.hxx>
50 #include <sfx2/objsh.hxx>
51 #include <sfx2/docfile.hxx>
52 #include <sfx2/viewfrm.hxx>
53 #include <comphelper/propertysequence.hxx>
58 /// Returns the URL of this object shell.
59 OUString
lcl_getOwnURL(SfxObjectShell
const * pObjectShell
)
66 const INetURLObject
& rURLObject
= pObjectShell
->GetMedium()->GetURLObject();
67 aRet
= rURLObject
.GetMainURL(INetURLObject::DecodeMechanism::NONE
);
77 using namespace ::utl
;
78 using namespace ::comphelper
;
79 using namespace ::com::sun::star
;
80 using namespace ::com::sun::star::uno
;
81 using namespace ::com::sun::star::lang
;
82 using namespace ::com::sun::star::sdb
;
83 using namespace ::com::sun::star::sdbc
;
84 using namespace ::com::sun::star::task
;
85 using namespace ::com::sun::star::beans
;
86 using namespace ::com::sun::star::sdbcx
;
87 using namespace ::com::sun::star::container
;
88 using namespace ::com::sun::star::frame
;
90 static Reference
< XDatabaseContext
> lcl_getDataSourceContext( const Reference
< XComponentContext
>& _rxContext
)
92 Reference
<XDatabaseContext
> xContext
= DatabaseContext::create(_rxContext
);
97 /// creates a new data source and inserts it into the context
98 static void lcl_implCreateAndInsert(
99 const Reference
< XComponentContext
>& _rxContext
, const OUString
& _rName
,
100 Reference
< XPropertySet
>& /* [out] */ _rxNewDataSource
)
103 // get the data source context
104 Reference
< XDatabaseContext
> xContext
= lcl_getDataSourceContext( _rxContext
);
106 DBG_ASSERT( !xContext
->hasByName( _rName
), "lcl_implCreateAndInsert: name already used!" );
109 // create a new data source
110 Reference
< XPropertySet
> xNewDataSource
;
112 xNewDataSource
.set( xContext
->createInstance(), UNO_QUERY
);
113 DBG_ASSERT( xNewDataSource
.is(), "lcl_implCreateAndInsert: could not create a new data source!" );
116 // insert the data source into the context
117 DBG_ASSERT( xContext
.is(), "lcl_implCreateAndInsert: missing an interface on the context (XNamingService)!" );
120 // xDynamicContext->registerObject( _rName, xNewDataSource );
121 _rxNewDataSource
= std::move(xNewDataSource
);
126 /// creates and inserts a data source, and sets its URL property to the string given
127 static ODataSource
lcl_implCreateAndSetURL(
128 const Reference
< XComponentContext
>& _rxORB
, const OUString
& _rName
,
129 const char* _pInitialAsciiURL
)
131 ODataSource
aReturn( _rxORB
);
134 // create the new data source
135 Reference
< XPropertySet
> xNewDataSource
;
136 lcl_implCreateAndInsert( _rxORB
, _rName
, xNewDataSource
);
139 // set the URL property
140 if (xNewDataSource
.is())
142 xNewDataSource
->setPropertyValue(
144 Any( OUString::createFromAscii( _pInitialAsciiURL
) )
148 aReturn
.setDataSource( xNewDataSource
, _rName
);
150 catch(const Exception
&)
152 TOOLS_WARN_EXCEPTION("extensions.abpilot",
153 "caught an exception while creating the data source!");
159 static void lcl_registerDataSource(
160 const Reference
< XComponentContext
>& _rxORB
, const OUString
& _sName
,
161 const OUString
& _sURL
)
163 OSL_ENSURE( !_sName
.isEmpty(), "lcl_registerDataSource: invalid name!" );
164 OSL_ENSURE( !_sURL
.isEmpty(), "lcl_registerDataSource: invalid URL!" );
167 Reference
< XDatabaseContext
> xRegistrations( DatabaseContext::create(_rxORB
) );
168 if ( xRegistrations
->hasRegisteredDatabase( _sName
) )
169 xRegistrations
->changeDatabaseLocation( _sName
, _sURL
);
171 xRegistrations
->registerDatabaseLocation( _sName
, _sURL
);
173 catch( const Exception
& )
175 DBG_UNHANDLED_EXCEPTION("extensions.abpilot");
179 struct ODataSourceContextImpl
181 Reference
< XComponentContext
> xORB
;
182 Reference
< XNameAccess
> xContext
; /// the UNO data source context
183 StringBag aDataSourceNames
; /// for quicker name checks (without the UNO overhead)
185 explicit ODataSourceContextImpl(const Reference
< XComponentContext
>& _rxORB
)
189 ODataSourceContextImpl(const ODataSourceContextImpl
&) = delete;
190 ODataSourceContextImpl
& operator=(const ODataSourceContextImpl
&) = delete;
193 ODataSourceContext::ODataSourceContext(const Reference
< XComponentContext
>& _rxORB
)
194 :m_pImpl( new ODataSourceContextImpl( _rxORB
) )
198 // create the UNO context
199 m_pImpl
->xContext
.set( lcl_getDataSourceContext( _rxORB
), UNO_QUERY_THROW
);
201 // collect the data source names
202 for (auto& rDSName
: m_pImpl
->xContext
->getElementNames())
203 m_pImpl
->aDataSourceNames
.insert(rDSName
);
205 catch( const Exception
& )
207 TOOLS_WARN_EXCEPTION( "extensions.abpilot", "ODataSourceContext::ODataSourceContext" );
210 ODataSourceContext::~ODataSourceContext()
215 void ODataSourceContext::disambiguate(OUString
& _rDataSourceName
)
217 OUString
sCheck( _rDataSourceName
);
218 StringBag::const_iterator aPos
= m_pImpl
->aDataSourceNames
.find( sCheck
);
220 sal_Int32 nPostfix
= 1;
221 while ( ( m_pImpl
->aDataSourceNames
.end() != aPos
) && ( nPostfix
< 65535 ) )
222 { // there already is a data source with this name
223 sCheck
= _rDataSourceName
+ OUString::number( nPostfix
++ );
225 aPos
= m_pImpl
->aDataSourceNames
.find( sCheck
);
228 _rDataSourceName
= sCheck
;
232 void ODataSourceContext::getDataSourceNames( StringBag
& _rNames
) const
234 _rNames
= m_pImpl
->aDataSourceNames
;
237 ODataSource
ODataSourceContext::createNewThunderbird( const OUString
& _rName
)
239 return lcl_implCreateAndSetURL( m_pImpl
->xORB
, _rName
, "sdbc:address:thunderbird" );
243 ODataSource
ODataSourceContext::createNewEvolutionLdap( const OUString
& _rName
)
245 return lcl_implCreateAndSetURL( m_pImpl
->xORB
, _rName
, "sdbc:address:evolution:ldap" );
248 ODataSource
ODataSourceContext::createNewEvolutionGroupwise( const OUString
& _rName
)
250 return lcl_implCreateAndSetURL( m_pImpl
->xORB
, _rName
, "sdbc:address:evolution:groupwise" );
253 ODataSource
ODataSourceContext::createNewEvolution( const OUString
& _rName
)
255 return lcl_implCreateAndSetURL( m_pImpl
->xORB
, _rName
, "sdbc:address:evolution:local" );
259 ODataSource
ODataSourceContext::createNewKab( const OUString
& _rName
)
261 return lcl_implCreateAndSetURL( m_pImpl
->xORB
, _rName
, "sdbc:address:kab" );
265 ODataSource
ODataSourceContext::createNewMacab( const OUString
& _rName
)
267 return lcl_implCreateAndSetURL( m_pImpl
->xORB
, _rName
, "sdbc:address:macab" );
271 // tdf117101: Spreadsheet by default
272 ODataSource
ODataSourceContext::createNewOther( const OUString
& _rName
)
274 return lcl_implCreateAndSetURL( m_pImpl
->xORB
, _rName
, "sdbc:calc:" );
277 struct ODataSourceImpl
280 Reference
< XComponentContext
> xORB
; /// the service factory
281 Reference
< XPropertySet
> xDataSource
; /// the UNO data source
282 ::utl::SharedUNOComponent
< XConnection
>
284 StringBag aTables
; // the cached table names
287 explicit ODataSourceImpl(const Reference
< XComponentContext
>& _rxORB
)
294 ODataSource::ODataSource( const ODataSource
& _rSource
)
299 ODataSource
& ODataSource::operator=( const ODataSource
& _rSource
)
301 if( this != &_rSource
)
303 m_pImpl
.reset( new ODataSourceImpl( *_rSource
.m_pImpl
) );
308 ODataSource
& ODataSource::operator=(ODataSource
&& _rSource
) noexcept
310 m_pImpl
= std::move(_rSource
.m_pImpl
);
314 ODataSource::ODataSource( const Reference
< XComponentContext
>& _rxORB
)
315 :m_pImpl(new ODataSourceImpl(_rxORB
))
319 ODataSource::~ODataSource( )
323 void ODataSource::store(const AddressSettings
& rSettings
)
330 Reference
< XDocumentDataSource
> xDocAccess( m_pImpl
->xDataSource
, UNO_QUERY
);
331 Reference
< XStorable
> xStorable
;
332 if ( xDocAccess
.is() )
333 xStorable
.set(xDocAccess
->getDatabaseDocument(), css::uno::UNO_QUERY
);
334 OSL_ENSURE( xStorable
.is(),"DataSource is no XStorable!" );
335 if ( xStorable
.is() )
337 SfxViewFrame
* pFrame
= SfxViewFrame::Current();
338 SfxObjectShell
* pObjectShell
= pFrame
? pFrame
->GetObjectShell() : nullptr;
339 OUString aOwnURL
= lcl_getOwnURL(pObjectShell
); // empty if pObjectShell is nullptr
340 if (aOwnURL
.isEmpty() || !rSettings
.bEmbedDataSource
)
342 // Cannot or should not embed.
343 xStorable
->storeAsURL(m_pImpl
->sName
,Sequence
<PropertyValue
>());
348 OUString aStreamRelPath
= u
"EmbeddedDatabase"_ustr
;
349 const auto& xContext(comphelper::getProcessComponentContext());
350 auto xUri
= css::uri::UriReferenceFactory::create(xContext
)->parse(aOwnURL
);
352 xUri
= css::uri::VndSunStarPkgUrlReferenceFactory::create(xContext
)->createVndSunStarPkgUrlReference(xUri
);
354 OUString
const sTmpName
= xUri
->getUriReference() + "/" + aStreamRelPath
;
355 assert(pObjectShell
);
356 uno::Reference
<embed::XStorage
> xStorage
= pObjectShell
->GetStorage();
357 uno::Sequence
<beans::PropertyValue
> aSequence
= comphelper::InitPropertySequence(
359 {"TargetStorage", uno::Any(xStorage
)},
360 {"StreamRelPath", uno::Any(aStreamRelPath
)},
361 {"BaseURI", uno::Any(aOwnURL
)}
363 xStorable
->storeAsURL(sTmpName
, aSequence
);
364 m_pImpl
->sName
= sTmpName
;
366 // Refer to the sub-storage name in the document settings, so
367 // we can load it again next time the file is imported.
368 uno::Reference
<lang::XMultiServiceFactory
> xFactory(pObjectShell
->GetModel(), uno::UNO_QUERY
);
369 uno::Reference
<beans::XPropertySet
> xPropertySet(xFactory
->createInstance(u
"com.sun.star.document.Settings"_ustr
), uno::UNO_QUERY
);
370 xPropertySet
->setPropertyValue(u
"EmbeddedDatabaseName"_ustr
, uno::Any(aStreamRelPath
));
374 catch(const Exception
&)
376 TOOLS_WARN_EXCEPTION("extensions.abpilot",
377 "caught an exception while creating the data source!");
381 void ODataSource::registerDataSource( const OUString
& _sRegisteredDataSourceName
)
389 // invalidate ourself
390 lcl_registerDataSource(m_pImpl
->xORB
,_sRegisteredDataSourceName
,m_pImpl
->sName
);
392 catch(const Exception
&)
394 TOOLS_WARN_EXCEPTION("extensions.abpilot",
395 "caught an exception while creating the data source!");
400 void ODataSource::setDataSource( const Reference
< XPropertySet
>& _rxDS
,const OUString
& _sName
)
402 if (m_pImpl
->xDataSource
.get() == _rxDS
.get())
409 m_pImpl
->sName
= _sName
;
410 m_pImpl
->xDataSource
= _rxDS
;
414 void ODataSource::remove()
422 // invalidate ourself
423 m_pImpl
->xDataSource
.clear();
425 catch(const Exception
&)
427 TOOLS_WARN_EXCEPTION("extensions.abpilot",
428 "caught an exception while creating the data source!");
433 bool ODataSource::rename( const OUString
& _rName
)
439 m_pImpl
->sName
= _rName
;
444 const OUString
& ODataSource::getName() const
447 return EMPTY_OUSTRING
;
448 return m_pImpl
->sName
;
452 bool ODataSource::hasTable( const OUString
& _rTableName
) const
454 if ( !isConnected() )
457 const StringBag
& aTables( getTableNames() );
458 return aTables
.find( _rTableName
) != aTables
.end();
462 const StringBag
& ODataSource::getTableNames() const
464 m_pImpl
->aTables
.clear();
465 if ( !isConnected() )
467 OSL_FAIL( "ODataSource::getTableNames: not connected!" );
473 // get the tables container from the connection
474 Reference
< XTablesSupplier
> xSuppTables( m_pImpl
->xConnection
.getTyped(), UNO_QUERY
);
475 Reference
< XNameAccess
> xTables
;
476 if ( xSuppTables
.is( ) )
477 xTables
= xSuppTables
->getTables();
478 DBG_ASSERT( xTables
.is(), "ODataSource::getTableNames: could not retrieve the tables container!" );
481 Sequence
< OUString
> aTableNames
;
483 aTableNames
= xTables
->getElementNames( );
486 for (auto& rTableName
: aTableNames
)
487 m_pImpl
->aTables
.insert(rTableName
);
489 catch(const Exception
&)
494 // now the table cache is up-to-date
495 return m_pImpl
->aTables
;
499 bool ODataSource::connect(weld::Window
* _pMessageParent
)
501 if ( isConnected( ) )
506 // create the interaction handler (needed for authentication and error handling)
507 Reference
< XInteractionHandler
> xInteractions
;
510 xInteractions
= InteractionHandler::createWithParent(m_pImpl
->xORB
, nullptr);
512 catch(const Exception
&)
517 // failure to create the interaction handler is a serious issue ...
518 if (!xInteractions
.is())
520 if ( _pMessageParent
)
521 ShowServiceNotAvailableError( _pMessageParent
, u
"com.sun.star.task.InteractionHandler", true );
526 // open the connection
528 Reference
< XConnection
> xConnection
;
531 Reference
< XCompletedConnection
> xComplConn( m_pImpl
->xDataSource
, UNO_QUERY
);
532 DBG_ASSERT( xComplConn
.is(), "ODataSource::connect: missing the XCompletedConnection interface on the data source!" );
533 if ( xComplConn
.is() )
534 xConnection
= xComplConn
->connectWithCompletion( xInteractions
);
536 catch( const SQLContext
& e
) { aError
<<= e
; }
537 catch( const SQLWarning
& e
) { aError
<<= e
; }
538 catch( const SQLException
& e
) { aError
<<= e
; }
539 catch( const Exception
& )
541 TOOLS_WARN_EXCEPTION("extensions.abpilot", "");
546 if ( aError
.hasValue() && _pMessageParent
)
550 SQLException aException
;
551 aError
>>= aException
;
552 if ( aException
.Message
.isEmpty() )
554 // prepend some context info
555 SQLContext
aDetailedError(compmodule::ModuleRes(RID_STR_NOCONNECTION
), // message
557 aError
, // next exception
558 compmodule::ModuleRes(RID_STR_PLEASECHECKSETTINGS
)); // details
559 // handle (aka display) the new context info
560 xInteractions
->handle( new OInteractionRequest( Any( aDetailedError
) ) );
564 // handle (aka display) the original error
565 xInteractions
->handle( new OInteractionRequest( Any( aException
) ) );
568 catch( const Exception
& )
570 TOOLS_WARN_EXCEPTION("extensions.abpilot",
571 "caught an exception while trying to display the error!");
575 if ( !xConnection
.is() )
580 m_pImpl
->xConnection
.reset( xConnection
);
581 m_pImpl
->aTables
.clear();
587 void ODataSource::disconnect( )
589 m_pImpl
->xConnection
.clear();
590 m_pImpl
->aTables
.clear();
594 bool ODataSource::isConnected( ) const
596 return m_pImpl
->xConnection
.is();
600 bool ODataSource::isValid() const
602 return m_pImpl
&& m_pImpl
->xDataSource
.is();
605 Reference
< XPropertySet
> ODataSource::getDataSource() const
607 return m_pImpl
? m_pImpl
->xDataSource
: Reference
< XPropertySet
>();
614 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */