LibreOffice Module extensions (master) 1
datasourcehandling.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20
21#include <strings.hrc>
22#include "abptypes.hxx"
23#include <componentmodule.hxx>
25#include "addresssettings.hxx"
26
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>
42
45#include <tools/debug.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>
54
55namespace
56{
57
59OUString lcl_getOwnURL(SfxObjectShell const * pObjectShell)
60{
61 OUString aRet;
62
63 if (!pObjectShell)
64 return aRet;
65
66 const INetURLObject& rURLObject = pObjectShell->GetMedium()->GetURLObject();
68 return aRet;
69}
70
71}
72
73namespace abp
74{
75
76
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;
89
90 static Reference< XDatabaseContext > lcl_getDataSourceContext( const Reference< XComponentContext >& _rxContext )
91 {
92 Reference<XDatabaseContext> xContext = DatabaseContext::create(_rxContext);
93 return xContext;
94 }
95
96
99 const Reference< XComponentContext >& _rxContext, const OUString& _rName,
100 Reference< XPropertySet >& /* [out] */ _rxNewDataSource )
101 {
102
103 // get the data source context
104 Reference< XDatabaseContext > xContext = lcl_getDataSourceContext( _rxContext );
105
106 DBG_ASSERT( !xContext->hasByName( _rName ), "lcl_implCreateAndInsert: name already used!" );
107
108
109 // create a new data source
110 Reference< XPropertySet > xNewDataSource;
111 if (xContext.is())
112 xNewDataSource.set( xContext->createInstance(), UNO_QUERY );
113 DBG_ASSERT( xNewDataSource.is(), "lcl_implCreateAndInsert: could not create a new data source!" );
114
115
116 // insert the data source into the context
117 DBG_ASSERT( xContext.is(), "lcl_implCreateAndInsert: missing an interface on the context (XNamingService)!" );
118 if (xContext.is())
119 {
120 // xDynamicContext->registerObject( _rName, xNewDataSource );
121 _rxNewDataSource = xNewDataSource;
122 }
123 }
124
125
128 const Reference< XComponentContext >& _rxORB, const OUString& _rName,
129 const char* _pInitialAsciiURL )
130 {
131 ODataSource aReturn( _rxORB );
132 try
133 {
134 // create the new data source
135 Reference< XPropertySet > xNewDataSource;
136 lcl_implCreateAndInsert( _rxORB, _rName, xNewDataSource );
137
138
139 // set the URL property
140 if (xNewDataSource.is())
141 {
142 xNewDataSource->setPropertyValue(
143 "URL",
144 Any( OUString::createFromAscii( _pInitialAsciiURL ) )
145 );
146 }
147
148 aReturn.setDataSource( xNewDataSource, _rName );
149 }
150 catch(const Exception&)
151 {
152 TOOLS_WARN_EXCEPTION("extensions.abpilot",
153 "caught an exception while creating the data source!");
154 }
155
156 return aReturn;
157 }
158
160 const Reference< XComponentContext >& _rxORB, const OUString& _sName,
161 const OUString& _sURL )
162 {
163 OSL_ENSURE( !_sName.isEmpty(), "lcl_registerDataSource: invalid name!" );
164 OSL_ENSURE( !_sURL.isEmpty(), "lcl_registerDataSource: invalid URL!" );
165 try
166 {
167 Reference< XDatabaseContext > xRegistrations( DatabaseContext::create(_rxORB) );
168 if ( xRegistrations->hasRegisteredDatabase( _sName ) )
169 xRegistrations->changeDatabaseLocation( _sName, _sURL );
170 else
171 xRegistrations->registerDatabaseLocation( _sName, _sURL );
172 }
173 catch( const Exception& )
174 {
175 DBG_UNHANDLED_EXCEPTION("extensions.abpilot");
176 }
177 }
178
180 {
181 Reference< XComponentContext > xORB;
182 Reference< XNameAccess > xContext;
184
185 explicit ODataSourceContextImpl(const Reference< XComponentContext >& _rxORB)
186 : xORB(_rxORB)
187 {
188 }
191 };
192
193 ODataSourceContext::ODataSourceContext(const Reference< XComponentContext >& _rxORB)
194 :m_pImpl( new ODataSourceContextImpl( _rxORB ) )
195 {
196 try
197 {
198 // create the UNO context
199 m_pImpl->xContext.set( lcl_getDataSourceContext( _rxORB ), UNO_QUERY_THROW );
200
201 // collect the data source names
202 Sequence< OUString > aDSNames = m_pImpl->xContext->getElementNames();
203 const OUString* pDSNames = aDSNames.getConstArray();
204 const OUString* pDSNamesEnd = pDSNames + aDSNames.getLength();
205
206 for ( ;pDSNames != pDSNamesEnd; ++pDSNames )
207 m_pImpl->aDataSourceNames.insert( *pDSNames );
208 }
209 catch( const Exception& )
210 {
211 TOOLS_WARN_EXCEPTION( "extensions.abpilot", "ODataSourceContext::ODataSourceContext" );
212 }
213 }
215 {
216 }
217
218
219 void ODataSourceContext::disambiguate(OUString& _rDataSourceName)
220 {
221 OUString sCheck( _rDataSourceName );
222 StringBag::const_iterator aPos = m_pImpl->aDataSourceNames.find( sCheck );
223
224 sal_Int32 nPostfix = 1;
225 while ( ( m_pImpl->aDataSourceNames.end() != aPos ) && ( nPostfix < 65535 ) )
226 { // there already is a data source with this name
227 sCheck = _rDataSourceName + OUString::number( nPostfix++ );
228
229 aPos = m_pImpl->aDataSourceNames.find( sCheck );
230 }
231
232 _rDataSourceName = sCheck;
233 }
234
235
237 {
238 _rNames = m_pImpl->aDataSourceNames;
239 }
240
242 {
243 return lcl_implCreateAndSetURL( m_pImpl->xORB, _rName, "sdbc:address:thunderbird" );
244 }
245
246
248 {
249 return lcl_implCreateAndSetURL( m_pImpl->xORB, _rName, "sdbc:address:evolution:ldap" );
250 }
251
253 {
254 return lcl_implCreateAndSetURL( m_pImpl->xORB, _rName, "sdbc:address:evolution:groupwise" );
255 }
256
258 {
259 return lcl_implCreateAndSetURL( m_pImpl->xORB, _rName, "sdbc:address:evolution:local" );
260 }
261
262
264 {
265 return lcl_implCreateAndSetURL( m_pImpl->xORB, _rName, "sdbc:address:kab" );
266 }
267
268
270 {
271 return lcl_implCreateAndSetURL( m_pImpl->xORB, _rName, "sdbc:address:macab" );
272 }
273
274
275 // tdf117101: Spreadsheet by default
277 {
278 return lcl_implCreateAndSetURL( m_pImpl->xORB, _rName, "sdbc:calc:" );
279 }
280
282 {
283 public:
284 Reference< XComponentContext > xORB;
285 Reference< XPropertySet > xDataSource;
288 StringBag aTables; // the cached table names
289 OUString sName;
290
291 explicit ODataSourceImpl(const Reference< XComponentContext >& _rxORB)
292 : xORB(_rxORB)
293 {
294 }
295 };
296
297
299 {
300 *this = _rSource;
301 }
302
304 {
305 if( this != &_rSource )
306 {
307 m_pImpl.reset( new ODataSourceImpl( *_rSource.m_pImpl ) );
308 }
309 return *this;
310 }
311
313 {
314 m_pImpl = std::move(_rSource.m_pImpl);
315 return *this;
316 }
317
318 ODataSource::ODataSource( const Reference< XComponentContext >& _rxORB )
319 :m_pImpl(new ODataSourceImpl(_rxORB))
320 {
321 }
322
324 {
325 }
326
327 void ODataSource::store(const AddressSettings& rSettings)
328 {
329 if (!isValid())
330 // nothing to do
331 return;
332 try
333 {
334 Reference< XDocumentDataSource > xDocAccess( m_pImpl->xDataSource, UNO_QUERY );
335 Reference< XStorable > xStorable;
336 if ( xDocAccess.is() )
337 xStorable.set(xDocAccess->getDatabaseDocument(), css::uno::UNO_QUERY);
338 OSL_ENSURE( xStorable.is(),"DataSource is no XStorable!" );
339 if ( xStorable.is() )
340 {
342 SfxObjectShell* pObjectShell = pFrame ? pFrame->GetObjectShell() : nullptr;
343 OUString aOwnURL = lcl_getOwnURL(pObjectShell); // empty if pObjectShell is nullptr
344 if (aOwnURL.isEmpty() || !rSettings.bEmbedDataSource)
345 {
346 // Cannot or should not embed.
347 xStorable->storeAsURL(m_pImpl->sName,Sequence<PropertyValue>());
348 }
349 else
350 {
351 // Embed.
352 OUString aStreamRelPath = "EmbeddedDatabase";
354 auto xUri = css::uri::UriReferenceFactory::create(xContext)->parse(aOwnURL);
355 assert(xUri.is());
356 xUri = css::uri::VndSunStarPkgUrlReferenceFactory::create(xContext)->createVndSunStarPkgUrlReference(xUri);
357 assert(xUri.is());
358 OUString const sTmpName = xUri->getUriReference() + "/" + aStreamRelPath;
359 assert(pObjectShell);
360 uno::Reference<embed::XStorage> xStorage = pObjectShell->GetStorage();
361 uno::Sequence<beans::PropertyValue> aSequence = comphelper::InitPropertySequence(
362 {
363 {"TargetStorage", uno::Any(xStorage)},
364 {"StreamRelPath", uno::Any(aStreamRelPath)},
365 {"BaseURI", uno::Any(aOwnURL)}
366 });
367 xStorable->storeAsURL(sTmpName, aSequence);
368 m_pImpl->sName = sTmpName;
369
370 // Refer to the sub-storage name in the document settings, so
371 // we can load it again next time the file is imported.
372 uno::Reference<lang::XMultiServiceFactory> xFactory(pObjectShell->GetModel(), uno::UNO_QUERY);
373 uno::Reference<beans::XPropertySet> xPropertySet(xFactory->createInstance("com.sun.star.document.Settings"), uno::UNO_QUERY);
374 xPropertySet->setPropertyValue("EmbeddedDatabaseName", uno::Any(aStreamRelPath));
375 }
376 }
377 }
378 catch(const Exception&)
379 {
380 TOOLS_WARN_EXCEPTION("extensions.abpilot",
381 "caught an exception while creating the data source!");
382 }
383 }
384
385 void ODataSource::registerDataSource( const OUString& _sRegisteredDataSourceName)
386 {
387 if (!isValid())
388 // nothing to do
389 return;
390
391 try
392 {
393 // invalidate ourself
394 lcl_registerDataSource(m_pImpl->xORB,_sRegisteredDataSourceName,m_pImpl->sName);
395 }
396 catch(const Exception&)
397 {
398 TOOLS_WARN_EXCEPTION("extensions.abpilot",
399 "caught an exception while creating the data source!");
400 }
401 }
402
403
404 void ODataSource::setDataSource( const Reference< XPropertySet >& _rxDS,const OUString& _sName )
405 {
406 if (m_pImpl->xDataSource.get() == _rxDS.get())
407 // nothing to do
408 return;
409
410 if ( isConnected() )
411 disconnect();
412
413 m_pImpl->sName = _sName;
414 m_pImpl->xDataSource = _rxDS;
415 }
416
417
419 {
420 if (!isValid())
421 // nothing to do
422 return;
423
424 try
425 {
426 // invalidate ourself
427 m_pImpl->xDataSource.clear();
428 }
429 catch(const Exception&)
430 {
431 TOOLS_WARN_EXCEPTION("extensions.abpilot",
432 "caught an exception while creating the data source!");
433 }
434 }
435
436
437 bool ODataSource::rename( const OUString& _rName )
438 {
439 if (!isValid())
440 // nothing to do
441 return false;
442
443 m_pImpl->sName = _rName;
444 return true;
445 }
446
447
448 OUString ODataSource::getName() const
449 {
450 if ( !isValid() )
451 return OUString();
452 return m_pImpl->sName;
453 }
454
455
456 bool ODataSource::hasTable( const OUString& _rTableName ) const
457 {
458 if ( !isConnected() )
459 return false;
460
461 const StringBag& aTables( getTableNames() );
462 return aTables.find( _rTableName ) != aTables.end();
463 }
464
465
467 {
468 m_pImpl->aTables.clear();
469 if ( !isConnected() )
470 {
471 OSL_FAIL( "ODataSource::getTableNames: not connected!" );
472 }
473 else
474 {
475 try
476 {
477 // get the tables container from the connection
478 Reference< XTablesSupplier > xSuppTables( m_pImpl->xConnection.getTyped(), UNO_QUERY );
479 Reference< XNameAccess > xTables;
480 if ( xSuppTables.is( ) )
481 xTables = xSuppTables->getTables();
482 DBG_ASSERT( xTables.is(), "ODataSource::getTableNames: could not retrieve the tables container!" );
483
484 // get the names
485 Sequence< OUString > aTableNames;
486 if ( xTables.is( ) )
487 aTableNames = xTables->getElementNames( );
488
489 // copy the names
490 const OUString* pTableNames = aTableNames.getConstArray();
491 const OUString* pTableNamesEnd = pTableNames + aTableNames.getLength();
492 for (;pTableNames < pTableNamesEnd; ++pTableNames)
493 m_pImpl->aTables.insert( *pTableNames );
494 }
495 catch(const Exception&)
496 {
497 }
498 }
499
500 // now the table cache is up-to-date
501 return m_pImpl->aTables;
502 }
503
504
505 bool ODataSource::connect(weld::Window* _pMessageParent)
506 {
507 if ( isConnected( ) )
508 // nothing to do
509 return true;
510
511
512 // create the interaction handler (needed for authentication and error handling)
513 Reference< XInteractionHandler > xInteractions;
514 try
515 {
516 xInteractions = InteractionHandler::createWithParent(m_pImpl->xORB, nullptr);
517 }
518 catch(const Exception&)
519 {
520 }
521
522
523 // failure to create the interaction handler is a serious issue ...
524 if (!xInteractions.is())
525 {
526 if ( _pMessageParent )
527 ShowServiceNotAvailableError( _pMessageParent, u"com.sun.star.task.InteractionHandler", true );
528 return false;
529 }
530
531
532 // open the connection
533 Any aError;
534 Reference< XConnection > xConnection;
535 try
536 {
537 Reference< XCompletedConnection > xComplConn( m_pImpl->xDataSource, UNO_QUERY );
538 DBG_ASSERT( xComplConn.is(), "ODataSource::connect: missing the XCompletedConnection interface on the data source!" );
539 if ( xComplConn.is() )
540 xConnection = xComplConn->connectWithCompletion( xInteractions );
541 }
542 catch( const SQLContext& e ) { aError <<= e; }
543 catch( const SQLWarning& e ) { aError <<= e; }
544 catch( const SQLException& e ) { aError <<= e; }
545 catch( const Exception& )
546 {
547 TOOLS_WARN_EXCEPTION("extensions.abpilot", "");
548 }
549
550
551 // handle errors
552 if ( aError.hasValue() && _pMessageParent )
553 {
554 try
555 {
556 SQLException aException;
557 aError >>= aException;
558 if ( aException.Message.isEmpty() )
559 {
560 // prepend some context info
561 SQLContext aDetailedError;
562 aDetailedError.Message = compmodule::ModuleRes(RID_STR_NOCONNECTION);
563 aDetailedError.Details = compmodule::ModuleRes(RID_STR_PLEASECHECKSETTINGS);
564 aDetailedError.NextException = aError;
565 // handle (aka display) the new context info
566 xInteractions->handle( new OInteractionRequest( Any( aDetailedError ) ) );
567 }
568 else
569 {
570 // handle (aka display) the original error
571 xInteractions->handle( new OInteractionRequest( Any( aException ) ) );
572 }
573 }
574 catch( const Exception& )
575 {
576 TOOLS_WARN_EXCEPTION("extensions.abpilot",
577 "caught an exception while trying to display the error!");
578 }
579 }
580
581 if ( !xConnection.is() )
582 return false;
583
584
585 // success
586 m_pImpl->xConnection.reset( xConnection );
587 m_pImpl->aTables.clear();
588
589 return true;
590 }
591
592
594 {
595 m_pImpl->xConnection.clear();
596 m_pImpl->aTables.clear();
597 }
598
599
601 {
602 return m_pImpl->xConnection.is();
603 }
604
605
607 {
608 return m_pImpl && m_pImpl->xDataSource.is();
609 }
610
611 Reference< XPropertySet > ODataSource::getDataSource() const
612 {
613 return m_pImpl ? m_pImpl->xDataSource : Reference< XPropertySet >();
614 }
615
616
617} // namespace abp
618
619
620/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
::std::unique_ptr< XmlIdRegistry_Impl > m_pImpl
OUString GetMainURL(DecodeMechanism eMechanism, rtl_TextEncoding eCharset=RTL_TEXTENCODING_UTF8) const
const INetURLObject & GetURLObject() const
SfxMedium * GetMedium() const
css::uno::Reference< css::frame::XModel3 > GetModel() const
css::uno::Reference< css::embed::XStorage > const & GetStorage()
static SAL_WARN_UNUSED_RESULT SfxViewFrame * Current()
virtual SfxObjectShell * GetObjectShell() override
ODataSource createNewEvolutionGroupwise(const OUString &_rName)
creates a new Evolution GROUPWISE data source
ODataSource createNewEvolutionLdap(const OUString &_rName)
creates a new Evolution LDAP data source
ODataSourceContext(const css::uno::Reference< css::uno::XComponentContext > &_rxORB)
ODataSource createNewKab(const OUString &_rName)
creates a new KDE address book data source
ODataSource createNewMacab(const OUString &_rName)
creates a new macOS address book data source
std::unique_ptr< ODataSourceContextImpl > m_pImpl
void disambiguate(OUString &_rDataSourceName)
disambiguates the given name by appending successive numbers
void getDataSourceNames(StringBag &_rNames) const
retrieves the names of all data sources
ODataSource createNewOther(const OUString &_rName)
creates a new Other data source; tdf117101: Spreadsheet by default
ODataSource createNewEvolution(const OUString &_rName)
creates a new Evolution local data source
ODataSource createNewThunderbird(const OUString &_rName)
creates a new Thunderbird data source
a non-UNO wrapper for a data source
void store(const AddressSettings &rSettings)
stores the database file
bool connect(weld::Window *_pMessageParent)
connects to the data source represented by this object
void remove()
removes the data source represented by the object from the data source context
bool isValid() const
checks whether or not the object represents a valid data source
void setDataSource(const css::uno::Reference< css::beans::XPropertySet > &_rxDS, const OUString &_sName)
set a new data source.
void disconnect()
disconnects from the data source (i.e. disposes the UNO connection hold internally)
std::unique_ptr< ODataSourceImpl > m_pImpl
bool rename(const OUString &_rName)
renames the data source
const StringBag & getTableNames() const
retrieves the tables names from the connection
ODataSource(const css::uno::Reference< css::uno::XComponentContext > &_rxORB)
constructs an object which is initially invalid
bool hasTable(const OUString &_rTableName) const
determines whether a given table exists
void registerDataSource(const OUString &_sRegisteredDataSourceName)
register the data source under the given name in the configuration
ODataSource & operator=(const ODataSource &_rSource)
copy assignment
css::uno::Reference< css::beans::XPropertySet > getDataSource() const
return the internal data source object
OUString getName() const
returns the name of the data source
bool isConnected() const
returns <TRUE> if the object has a valid connection, obtained from its data source
#define DBG_ASSERT(sCon, aError)
#define TOOLS_WARN_EXCEPTION(area, stream)
#define DBG_UNHANDLED_EXCEPTION(...)
float u
Reference< XSingleServiceFactory > xFactory
static ODataSource lcl_implCreateAndSetURL(const Reference< XComponentContext > &_rxORB, const OUString &_rName, const char *_pInitialAsciiURL)
creates and inserts a data source, and sets its URL property to the string given
static void lcl_implCreateAndInsert(const Reference< XComponentContext > &_rxContext, const OUString &_rName, Reference< XPropertySet > &_rxNewDataSource)
creates a new data source and inserts it into the context
static Reference< XDatabaseContext > lcl_getDataSourceContext(const Reference< XComponentContext > &_rxContext)
std::set< OUString > StringBag
Definition: abptypes.hxx:34
static void lcl_registerDataSource(const Reference< XComponentContext > &_rxORB, const OUString &_sName, const OUString &_sURL)
@ Exception
Reference< XComponentContext > getProcessComponentContext()
css::uno::Sequence< css::beans::PropertyValue > InitPropertySequence(::std::initializer_list< ::std::pair< OUString, css::uno::Any > > vInit)
OUString ModuleRes(TranslateId pId)
void VCL_DLLPUBLIC ShowServiceNotAvailableError(weld::Widget *pParent, std::u16string_view rServiceName, bool bError)
Reference< XNameAccess > xContext
StringBag aDataSourceNames
the UNO data source context
Reference< XComponentContext > xORB
ODataSourceContextImpl & operator=(const ODataSourceContextImpl &)=delete
ODataSourceContextImpl(const ODataSourceContextImpl &)=delete
ODataSourceContextImpl(const Reference< XComponentContext > &_rxORB)
for quicker name checks (without the UNO overhead)
ODataSourceImpl(const Reference< XComponentContext > &_rxORB)
Reference< XPropertySet > xDataSource
the service factory
Reference< XComponentContext > xORB
::utl::SharedUNOComponent< XConnection > xConnection
the UNO data source