/* -*- 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 .
*/
/// Listens to removed data sources, and if it's one that's embedded into this document, triggers embedding removal. class SwDataSourceRemovedListener : public cppu::WeakImplHelper<sdb::XDatabaseRegistrationsListener>
{
uno::Reference<sdb::XDatabaseContext> m_xDatabaseContext;
SwDBManager* m_pDBManager;
// The revoked database location is inside this document, then remove the // embedding, as otherwise it would be back on the next reload of the // document.
pDocShell->GetStorage()->removeElement(m_pDBManager->getEmbeddedName());
m_pDBManager->setEmbeddedName(OUString(), *pDocShell);
}
m_pImpl->pMergeData.reset(new SwDSParam(aData, xResSet, aSelection));
SwDSParam* pTemp = FindDSData(aData, false); if(pTemp)
*pTemp = *m_pImpl->pMergeData; else
{ // calls from the calculator may have added a connection with an invalid commandtype //"real" data base connections added here have to re-use the already available //DSData and set the correct CommandType
aData.nCommandType = -1;
pTemp = FindDSData(aData, false); if(pTemp)
*pTemp = *m_pImpl->pMergeData; else
{
m_DataSourceParams.push_back(std::make_unique<SwDSParam>(*m_pImpl->pMergeData)); try
{
uno::Reference<lang::XComponent> xComponent(m_DataSourceParams.back()->xConnection, uno::UNO_QUERY); if(xComponent.is())
xComponent->addEventListener(m_pImpl->m_xDisposeListener);
} catch(const uno::Exception&)
{
}
}
} if(!m_pImpl->pMergeData->xConnection.is())
m_pImpl->pMergeData->xConnection = xConnection; // add an XEventListener
case DBMGR_MERGE_PRINTER: case DBMGR_MERGE_EMAIL: case DBMGR_MERGE_FILE: case DBMGR_MERGE_SHELL: // save files and send them as e-Mail if required
bRet = MergeMailFiles(pWorkShell, rMergeDesc); break;
// copy required, m_DataSourceParams can be modified while disposing components
std::vector<uno::Reference<sdbc::XConnection>> aCopiedConnections; for (constauto & pParam : m_DataSourceParams)
{ if(pParam->xConnection.is())
{
aCopiedConnections.push_back(pParam->xConnection);
}
} for (constauto & xConnection : aCopiedConnections)
{ try
{
uno::Reference<lang::XComponent> xComp(xConnection, uno::UNO_QUERY); if(xComp.is())
xComp->dispose();
} catch(const uno::RuntimeException&)
{ //may be disposed already since multiple entries may have used the same connection
}
}
}
// convert fields to text if we are exporting to PDF. // this prevents a second merge while updating the fields // in SwXTextDocument::getRendererCount() if( bIsPDFexport )
rWorkShell.ConvertFieldsToText();
bool bAnyError = !xObjectShell->DoSaveAs(*pDstMed); // Actually this should be a bool... so in case of email and individual // files, where this is set, we skip the recently used handling
bAnyError |= !xObjectShell->DoSaveCompleted( pDstMed, !decodedURL );
bAnyError |= (ERRCODE_NONE != xObjectShell->GetErrorIgnoreWarning()); if( bAnyError )
{ // error message ??
ErrorHandler::HandleError( xObjectShell->GetErrorIgnoreWarning() );
} return !bAnyError;
}
staticvoid lcl_PreparePrinterOptions( const uno::Sequence< beans::PropertyValue >& rInPrintOptions,
uno::Sequence< beans::PropertyValue >& rOutPrintOptions)
{ // printing should be done synchronously otherwise the document // might already become invalid during the process
if( pSourceWindow )
{ // the created window has to be located at the same position as the source window
vcl::Window& rTargetWindow = pWorkFrame->GetFrame().GetWindow();
rTargetWindow.SetPosPixel( pSourceWindow->GetPosPixel() );
}
if (SwWrtShell* pWorkWrtShell = pWorkView->GetWrtShellPtr())
{
pWorkWrtShell->GetViewOptions()->SetIdle( false );
pWorkView->AttrChangedNotify(nullptr);// in order for SelectShell to be called
SwDoc* pWorkDoc = pWorkWrtShell->GetDoc();
pWorkDoc->GetIDocumentUndoRedo().DoUndo( false );
pWorkDoc->ReplaceDocumentProperties( *pSourceDoc );
if( aType == WorkingDocType::TARGET )
{
assert( !ppDBManager );
pWorkDoc->SetInMailMerge( true );
pWorkWrtShell->SetLabelDoc( false );
} else
{ // We have to swap the DBmanager of the new doc, so we also need input
assert(ppDBManager && *ppDBManager);
SwDBManager *pWorkDBManager = pWorkDoc->GetDBManager();
pWorkDoc->SetDBManager( *ppDBManager );
*ppDBManager = pWorkDBManager;
if( aType == WorkingDocType::SOURCE )
{ // the GetDBData call constructs the data, if it's missing - kind of const...
pWorkWrtShell->ChgDBData( const_cast<SwDoc*>(pSourceDoc)->GetDBData() ); // some DocumentSettings are currently not copied by SwDoc::CreateCopy
pWorkWrtShell->SetLabelDoc( rSourceWrtShell.IsLabelDoc() );
pWorkDoc->getIDocumentState().ResetModified();
} else
pWorkDoc->getIDocumentLinksAdministration().EmbedAllLinks();
}
/** * Please have a look at the README in the same directory, before you make * larger changes in this function!
*/ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell, const SwMergeDescriptor& rMergeDescriptor)
{ // deconstruct mail merge type for better readability. // uppercase naming is intentional! constbool bMT_EMAIL = rMergeDescriptor.nMergeType == DBMGR_MERGE_EMAIL; constbool bMT_SHELL = rMergeDescriptor.nMergeType == DBMGR_MERGE_SHELL; constbool bMT_PRINTER = rMergeDescriptor.nMergeType == DBMGR_MERGE_PRINTER; constbool bMT_FILE = rMergeDescriptor.nMergeType == DBMGR_MERGE_FILE;
//check if the doc is synchronized and contains at least one linked section constbool bSynchronizedDoc = pSourceShell->IsLabelDoc() && pSourceShell->GetSectionFormatCount() > 1; constbool bNeedsTempFiles = ( bMT_EMAIL || bMT_FILE ); constbool bIsMergeSilent = IsMergeSilent();
// setup the output format
std::shared_ptr<const SfxFilter> pStoreToFilter = SwIoSystem::GetFileFilter(
pSourceDocSh->GetMedium()->GetURLObject().GetMainURL(INetURLObject::DecodeMechanism::NONE));
SfxFilterContainer* pFilterContainer = SwDocShell::Factory().GetFilterContainer(); const OUString* pStoreToFilterOptions = nullptr;
// if a save_to filter is set then use it - otherwise use the default if( bMT_EMAIL && !rMergeDescriptor.bSendAsAttachment )
{
OUString sExtension = rMergeDescriptor.bSendAsHTML ? u"html"_ustr : u"txt"_ustr;
pStoreToFilter = pFilterContainer->GetFilter4Extension(sExtension, SfxFilterFlags::EXPORT);
} elseif( !rMergeDescriptor.sSaveToFilter.isEmpty())
{
std::shared_ptr<const SfxFilter> pFilter =
pFilterContainer->GetFilter4FilterName( rMergeDescriptor.sSaveToFilter ); if(pFilter)
{
pStoreToFilter = std::move(pFilter); if(!rMergeDescriptor.sSaveToFilterOptions.isEmpty())
pStoreToFilterOptions = &rMergeDescriptor.sSaveToFilterOptions;
}
} constbool bIsPDFexport = pStoreToFilter && pStoreToFilter->GetFilterName() == "writer_pdf_Export"; constbool bIsMultiFile = bMT_FILE && !bCreateSingleFile;
m_aMergeStatus = MergeStatus::Ok;
// in case of creating a single resulting file this has to be created here
SwView* pTargetView = rMergeDescriptor.pMailMergeConfigItem ?
rMergeDescriptor.pMailMergeConfigItem->GetTargetView() : nullptr;
SwWrtShell* pTargetShell = nullptr;
SfxObjectShellRef xTargetDocShell;
rtl::Reference<SwDoc> pTargetDoc;
if( bCreateSingleFile )
{ // determine the page style and number used at the start of the source document
pSourceShell->SttEndDoc(true);
nStartingPageNo = pSourceShell->GetVirtPageNum();
}
// Progress, to prohibit KeyInputs
SfxProgress aProgress(pSourceDocSh, OUString(), 1);
// lock all dispatchers
SfxViewFrame* pViewFrame = SfxViewFrame::GetFirst(pSourceDocSh); while (pViewFrame)
{
pViewFrame->GetDispatcher()->Lock(true);
pViewFrame = SfxViewFrame::GetNext(*pViewFrame, pSourceDocSh);
}
sal_Int32 nDocNo = 1;
// For single file mode, the number of pages in the target document so far, which is used // by AppendDoc() to adjust position of page-bound objects. Getting this information directly // from the target doc would require repeated layouts of the doc, which is expensive, but // it can be manually computed from the source documents (for which we do layouts, so the page // count is known, and there is a blank page between each of them in the target document). int targetDocPageCount = 0;
// Synchronized docs don't auto-advance the record set, but there is a // "security" check, which will always advance the record set, if there // is no "next record" field in a synchronized doc => nRecordPerDoc > 0
sal_Int32 nRecordPerDoc = pSourceShell->GetDoc()
->getIDocumentFieldsAccess().GetRecordsPerDocument(); if ( bSynchronizedDoc && (nRecordPerDoc > 1) )
--nRecordPerDoc;
assert( nRecordPerDoc > 0 );
// The SfxObjectShell will be closed explicitly later but // it is more safe to use SfxObjectShellLock here
SfxObjectShellLock xWorkDocSh;
SwView* pWorkView = nullptr;
rtl::Reference<SwDoc> pWorkDoc;
SwDBManager* pWorkDocOrigDBManager = nullptr;
SwWrtShell* pWorkShell = nullptr; bool bWorkDocInitialized = false;
do
{
nStartRow = m_pImpl->pMergeData ? m_pImpl->pMergeData->xResultSet->getRow() : 0;
OUString sColumnData;
// Read the indicated data column, which should contain a valid mail // address or an optional file name if( bMT_EMAIL || bColumnName )
{
sColumnData = GetDBField( xColumnProp, aColumnDBFormat );
}
// create a new temporary file name - only done once in case of bCreateSingleFile if( bNeedsTempFiles && ( !bWorkDocInitialized || !bCreateSingleFile ))
{
OUString sPrefix = sDescriptorPrefix;
OUString sLeading;
//#i97667# if the name is from a database field then it will be used _as is_ if( bColumnName && !bMT_EMAIL )
{ if (!sColumnData.isEmpty())
sLeading = sColumnData; else
sLeading = u"_"_ustr;
} else
{
INetURLObject aEntry( sPrefix );
sLeading = aEntry.GetBase();
aEntry.removeSegment();
sPrefix = aEntry.GetMainURL( INetURLObject::DecodeMechanism::NONE );
}
// Create a copy of the source document and work with that one instead of the source. // If we're not in the single file mode (which requires modifying the document for the merging), // it is enough to do this just once. Currently PDF also has to be treated special. if( !bWorkDocInitialized || bCreateSingleFile || bIsPDFexport || bIsMultiFile )
{
assert( !xWorkDocSh.Is());
pWorkDocOrigDBManager = this;
xWorkDocSh = lcl_CreateWorkingDocument( WorkingDocType::COPY,
*pSourceShell, nullptr, &pWorkDocOrigDBManager,
&pWorkView, &pWorkShell, &pWorkDoc ); if ( (nMaxDumpDocs < 0) || (nDocNo <= nMaxDumpDocs) )
lcl_SaveDebugDoc( xWorkDocSh, "WorkDoc", nDocNo );
// #i69458# lock fields to prevent access to the result set while calculating layout // tdf#92324: and do not unlock: keep document locked during printing to avoid // ExpFields update during printing, generation of preview, etc.
pWorkShell->LockExpFields();
pWorkShell->CalcLayout(); // tdf#121168: Now force correct page descriptions applied to page frames. Without // this, e.g., page frames starting with sections could have page descriptions set // wrong. This would lead to wrong page styles applied in SwDoc::AppendDoc below.
pWorkShell->GetViewOptions()->SetIdle(true); for (auto aLayout : pWorkShell->GetDoc()->GetAllLayouts())
{
aLayout->FreezeLayout(false);
aLayout->AllCheckPageDescs();
}
}
// tdf#92324: Allow ExpFields update only by explicit instruction to avoid // database cursor movement on any other fields update, for example during // print preview and other operations if ( pWorkShell->IsExpFieldsLocked() )
pWorkShell->UnlockExpFields();
pWorkShell->SwViewShell::UpdateFields();
pWorkShell->LockExpFields();
pWorkDoc->RemoveInvisibleContent(); // remove of invisible content has influence on page count and so on fields for page count, // therefore layout has to be updated before fields are converted to text
pWorkShell->CalcLayout();
pWorkShell->ConvertFieldsToText();
pWorkShell->SetNumberingRestart(); if( bSynchronizedDoc )
{
lcl_RemoveSectionLinks( *pWorkShell );
}
// Freeze the layouts of the target document after the first inserted // sub-document, to get the correct PageDesc. if(!bFreezedLayouts && bCreateSingleFile)
{ for ( auto aLayout : pTargetShell->GetDoc()->GetAllLayouts() )
aLayout->FreezeLayout(true);
bFreezedLayouts = true;
}
} while( IsMergeOk() &&
((bSynchronizedDoc && (nStartRow != nEndRow)) ? IsValidMergeRecord() : ToNextMergeRecord()));
if ( xWorkDocSh.Is() && pWorkView->GetWrtShell().IsExpFieldsLocked() )
{ // Unlock document fields after merge complete
pWorkView->GetWrtShell().UnlockExpFields();
}
// sw::DocumentLayoutManager::CopyLayoutFormat() did not generate // unique fly names, do it here once.
pTargetDoc->SetInMailMerge(false);
pTargetDoc->SetAllUniqueFlyNames();
// Unfreeze target document layouts and correct all PageDescs.
SAL_INFO( "sw.pageframe", "(MergeMailFiles pTargetShell->CalcLayout in" );
pTargetShell->CalcLayout();
SAL_INFO( "sw.pageframe", "MergeMailFiles pTargetShell->CalcLayout out)" );
pTargetShell->GetViewOptions()->SetIdle( true );
pTargetDoc->GetIDocumentUndoRedo().DoUndo( true ); for ( auto aLayout : pTargetShell->GetDoc()->GetAllLayouts() )
{
aLayout->FreezeLayout(false);
aLayout->AllCheckPageDescs();
}
// we also show canceled documents, as long as there was no error if( !IsMergeError() && bMT_SHELL ) // leave docshell available for caller (e.g. MM wizard)
rMergeDescriptor.pMailMergeConfigItem->SetTargetView( pTargetView ); elseif( xTargetDocShell.is() )
xTargetDocShell->DoClose();
Application::Reschedule( true );
if (xProgressDlg)
{
xProgressDlg->response(RET_OK);
}
// unlock all dispatchers
pViewFrame = SfxViewFrame::GetFirst(pSourceDocSh); while (pViewFrame)
{
pViewFrame->GetDispatcher()->Lock(false);
pViewFrame = SfxViewFrame::GetNext(*pViewFrame, pSourceDocSh);
}
if( xMailDispatcher.is() )
{ if( IsMergeOk() )
{ // TODO: Instead of polling via an AutoTimer, post an Idle event, // if the main loop has been made thread-safe.
AutoTimer aEmailDispatcherPollTimer("sw::SwDBManager aEmailDispatcherPollTimer");
aEmailDispatcherPollTimer.SetTimeout( 500 );
aEmailDispatcherPollTimer.Start(); while( IsMergeOk() && m_pImpl->m_xLastMessage.is() && !Application::IsQuit())
Application::Yield();
aEmailDispatcherPollTimer.Stop();
}
xMailDispatcher->stop();
xMailDispatcher->shutdown();
}
// remove the temporary files // has to be done after xMailDispatcher is finished, as mails may be // delivered as message attachments! for( const OUString &sFileURL : aFilesToRemove )
SWUnoHelper::UCB_DeleteFile( sFileURL );
} catch (const uno::Exception&)
{ if (xProgressDlg)
{
xProgressDlg->response(RET_CANCEL);
}
}
uno::Any aType = xColumnProps->getPropertyValue(u"Type"_ustr);
sal_Int32 eDataType = sdbc::DataType::SQLNULL;
aType >>= eDataType; switch(eDataType)
{ case sdbc::DataType::CHAR: case sdbc::DataType::VARCHAR: case sdbc::DataType::LONGVARCHAR: try
{
sRet = xColumn->getString();
sRet = sRet.replace( '\xb', '\n' ); // MSWord uses \xb as a newline
} catch(const sdbc::SQLException&)
{
} break; case sdbc::DataType::BIT: case sdbc::DataType::BOOLEAN: case sdbc::DataType::TINYINT: case sdbc::DataType::SMALLINT: case sdbc::DataType::INTEGER: case sdbc::DataType::BIGINT: case sdbc::DataType::FLOAT: case sdbc::DataType::REAL: case sdbc::DataType::DOUBLE: case sdbc::DataType::NUMERIC: case sdbc::DataType::DECIMAL: case sdbc::DataType::DATE: case sdbc::DataType::TIME: case sdbc::DataType::TIMESTAMP:
{
// read column data at a specified position bool SwDBManager::GetColumnCnt(const OUString& rSourceName, const OUString& rTableName, const OUString& rColumnName, sal_uInt32 nAbsRecordId,
LanguageType nLanguage,
OUString& rResult, double* pNumber)
{ bool bRet = false;
SwDSParam* pFound = nullptr; //check if it's the merge data source if(m_pImpl->pMergeData &&
rSourceName == m_pImpl->pMergeData->sDataSource &&
rTableName == m_pImpl->pMergeData->sCommand)
{
pFound = m_pImpl->pMergeData.get();
} else
{
SwDBData aData;
aData.sDataSource = rSourceName;
aData.sCommand = rTableName;
aData.nCommandType = -1;
pFound = FindDSData(aData, false);
} if (!pFound) returnfalse; //check validity of supplied record Id if(pFound->aSelection.hasElements())
{ //the destination has to be an element of the selection bool bFound = std::any_of(std::cbegin(pFound->aSelection), std::cend(pFound->aSelection),
[nAbsRecordId](const uno::Any& rSelection) {
sal_Int32 nSelection = 0;
rSelection >>= nSelection; return nSelection == static_cast<sal_Int32>(nAbsRecordId);
}); if(!bFound) returnfalse;
} if( pFound->HasValidRecord() )
{
sal_Int32 nOldRow = 0; try
{
nOldRow = pFound->xResultSet->getRow();
} catch(const uno::Exception&)
{ returnfalse;
} //position to the desired index bool bMove = true; if ( nOldRow != static_cast<sal_Int32>(nAbsRecordId) )
bMove = lcl_MoveAbsolute(pFound, nAbsRecordId); if(bMove)
bRet = lcl_GetColumnCnt(pFound, rColumnName, nLanguage, rResult, pNumber); if ( nOldRow != static_cast<sal_Int32>(nAbsRecordId) )
lcl_MoveAbsolute(pFound, nOldRow);
} return bRet;
}
// reads the column data at the current position bool SwDBManager::GetMergeColumnCnt(const OUString& rColumnName, LanguageType nLanguage,
OUString &rResult, double *pNumber)
{ if( !IsValidMergeRecord() )
{
rResult.clear(); returnfalse;
}
++pParam->nSelectionIndex;
bRet = !pParam->bEndOfDB;
} catch( const uno::Exception & )
{ // we allow merging with empty databases, so don't warn on init
TOOLS_WARN_EXCEPTION_IF(action == SwDBNextRecord::NEXT, "sw.mailmerge", "exception in ToNextRecord()");
pParam->bEndOfDB = true;
bRet = false;
} return bRet;
}
// synchronized labels contain a next record field at their end // to assure that the next page can be created in mail merge // the cursor position must be validated bool SwDBManager::IsValidMergeRecord() const
{ return( m_pImpl->pMergeData && m_pImpl->pMergeData->HasValidRecord() );
}
// close all data sources - after fields were updated void SwDBManager::CloseAll(bool bIncludingMerge)
{ //the only thing done here is to reset the selection index //all connections stay open for (auto & pParam : m_DataSourceParams)
{ if (bIncludingMerge || pParam.get() != m_pImpl->pMergeData.get())
{
pParam->nSelectionIndex = 0;
pParam->bEndOfDB = false; try
{ if(!m_bInMerge && pParam->xResultSet.is())
pParam->xResultSet->first();
} catch(const uno::Exception&)
{}
}
}
}
/** Loads a data source from file and registers it.
In case of success it returns the registered name, otherwise an empty string. Optionally add a prefix to the registered DB name.
*/
OUString LoadAndRegisterDataSource_Impl(DBConnURIType type, const uno::Reference< beans::XPropertySet > *pSettings, const INetURLObject &rURL, const OUString *pDestDir, SfxObjectShell* pDocShell)
{
OUString sExt(rURL.GetFileExtension());
uno::Any aTableFilterAny;
uno::Any aSuppressVersionsAny;
uno::Any aInfoAny; bool bStore = true;
OUString sFind;
uno::Any aURLAny = GetDBunoURI(rURL, type); switch (type) { case DBConnURIType::UNKNOWN: case DBConnURIType::CALC: case DBConnURIType::WRITER: break; case DBConnURIType::ODB:
bStore = false; break; case DBConnURIType::FLAT: case DBConnURIType::DBASE: //set the filter to the file name without extension
{
uno::Sequence<OUString> aFilters { rURL.getBase(INetURLObject::LAST_SEGMENT, true, INetURLObject::DecodeMechanism::WithCharset) };
aTableFilterAny <<= aFilters;
} break; case DBConnURIType::MSACE:
aSuppressVersionsAny <<= true; break;
}
if (aURLAny.hasValue())
xDataProperties->setPropertyValue(u"URL"_ustr, aURLAny); if (aTableFilterAny.hasValue())
xDataProperties->setPropertyValue(u"TableFilter"_ustr, aTableFilterAny); if (aSuppressVersionsAny.hasValue())
xDataProperties->setPropertyValue(u"SuppressVersionColumns"_ustr, aSuppressVersionsAny); if (aInfoAny.hasValue())
xDataProperties->setPropertyValue(u"Info"_ustr, aInfoAny);
uno::Reference<sdb::XDocumentDataSource> xDS(xNewInstance, uno::UNO_QUERY_THROW);
uno::Reference<frame::XStorable> xStore(xDS->getDatabaseDocument(), uno::UNO_QUERY_THROW);
OUString aOwnURL = getOwnURL(pDocShell); if (aOwnURL.isEmpty())
{ // Cannot embed, as embedded data source would need the URL of the parent document.
OUString sHomePath(SvtPathOptions().GetWorkPath()); const OUString sTmpName = utl::CreateTempURL(sNewName, true, u".odb", pDestDir ? pDestDir : &sHomePath);
xStore->storeAsURL(sTmpName, uno::Sequence<beans::PropertyValue>());
} else
{ // Embed.
OUString aStreamRelPath = u"EmbeddedDatabase"_ustr;
uno::Reference<embed::XStorage> xStorage = pDocShell->GetStorage();
// Refer to the sub-storage name in the document settings, so // we can load it again next time the file is imported.
uno::Reference<lang::XMultiServiceFactory> xFactory(pDocShell->GetModel(), uno::UNO_QUERY);
uno::Reference<beans::XPropertySet> xPropertySet(xFactory->createInstance(u"com.sun.star.document.Settings"_ustr), uno::UNO_QUERY);
xPropertySet->setPropertyValue(u"EmbeddedDatabaseName"_ustr, uno::Any(aStreamRelPath));
// Store it only after setting the above property, so that only one data source gets registered.
SwDBManager::StoreEmbeddedDataSource(xStore, xStorage, aStreamRelPath, aOwnURL);
}
}
xDBContext->registerObject(sFind, xNewInstance);
} catch (const uno::Exception&)
{
sFind.clear();
} return sFind;
}
}
namespace
{ // tdf#117824 switch the embedded database away from using its current storage and point it to temporary storage // which allows the original storage to be deleted void switchEmbeddedDatabaseStorage(const uno::Reference<sdb::XDatabaseContext>& rDatabaseContext, const OUString& rName)
{
uno::Reference<sdb::XDocumentDataSource> xDS(rDatabaseContext->getByName(rName), uno::UNO_QUERY); if (!xDS) return;
uno::Reference<document::XStorageBasedDocument> xStorageDoc(xDS->getDatabaseDocument(), uno::UNO_QUERY); if (!xStorageDoc) return;
xStorageDoc->switchToStorage(comphelper::OStorageHelper::GetTemporaryStorage());
}
}
// Fallback, just in case the document would contain an embedded data source, but no DB fields. if (sDataSource.isEmpty())
sDataSource = u"EmbeddedDatabase"_ustr;
SwDBManager::RevokeDataSource( sDataSource );
// Encode the stream name and the real path into a single URL. const INetURLObject& rURLObject = rDocShell.GetMedium()->GetURLObject();
OUString const aURL = ConstructVndSunStarPkgUrl(
rURLObject.GetMainURL(INetURLObject::DecodeMechanism::NONE),
m_sEmbeddedName);
// SfxObjectShellRef is ok, since there should be no control over the document lifetime here
SfxObjectShellRef xDocShell = rSh.GetView().GetViewFrame().GetObjectShell();
// reset the cursor inside
xResSet = nullptr;
aDescriptor[svx::DataAccessDescriptorProperty::Cursor] <<= xResSet;
} if(pFound)
{ for (constauto & pParam : m_DataSourceParams)
{ if (pParam.get() == pFound)
{ try
{
uno::Reference<lang::XComponent> xComp(pParam->xConnection, uno::UNO_QUERY); if(xComp.is())
xComp->dispose();
} catch(const uno::RuntimeException&)
{ //may be disposed already since multiple entries may have used the same connection
} break;
} //pFound doesn't need to be removed/deleted - //this has been done by the SwConnectionDisposedListener_Impl already
}
}
m_pImpl->pMergeDialog.disposeAndClear();
}
if (bLoad)
{
uno::Reference<embed::XStorage> xStorage = rDocShell.GetStorage(); // It's OK that we don't have the named sub-storage yet, in case // we're in the process of creating it. if (xStorage->hasByName(rEmbeddedName))
LoadAndRegisterEmbeddedDataSource(rDocShell.GetDoc()->GetDBData(), rDocShell);
}
if (bRegisterListener) // Register a remove listener, so we know when the embedded data source is removed.
m_pImpl->m_xDataSourceRemovedListener = new SwDataSourceRemovedListener(*this);
}
for (auto it = s_aUncommittedRegistrations.begin(); it != s_aUncommittedRegistrations.end();)
{ if ((m_pDoc && it->first == m_pDoc->GetDocShell()) || it->first == nullptr)
{
RevokeDataSource(it->second);
it = s_aUncommittedRegistrations.erase(it);
} else
++it;
}
}
void SwDBManager::CommitLastRegistrations()
{ for (auto aIt = s_aUncommittedRegistrations.begin(); aIt != s_aUncommittedRegistrations.end();)
{ if (aIt->first == m_pDoc->GetDocShell() || aIt->first == nullptr)
{
m_aNotUsedConnections.push_back(aIt->second);
aIt = s_aUncommittedRegistrations.erase(aIt);
} else
aIt++;
}
}
void SwDBManager::SetAsUsed(const OUString& rName)
{ auto aFound = std::find(m_aNotUsedConnections.begin(), m_aNotUsedConnections.end(), rName); if (aFound != m_aNotUsedConnections.end())
m_aNotUsedConnections.erase(aFound);
}
void SwDBManager::RevokeNotUsedConnections()
{ for (auto aIt = m_aNotUsedConnections.begin(); aIt != m_aNotUsedConnections.end();)
{
RevokeDataSource(*aIt);
aIt = m_aNotUsedConnections.erase(aIt);
}
}
¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.76Angebot
(Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-05-08)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.