/src/libreoffice/comphelper/source/container/embeddedobjectcontainer.cxx
Line | Count | Source |
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 | | #include <com/sun/star/container/XChild.hpp> |
21 | | #include <com/sun/star/container/XNameAccess.hpp> |
22 | | #include <com/sun/star/embed/EmbeddedObjectCreator.hpp> |
23 | | #include <com/sun/star/embed/WrongStateException.hpp> |
24 | | #include <com/sun/star/embed/XEmbeddedObject.hpp> |
25 | | #include <com/sun/star/embed/XEmbedPersist.hpp> |
26 | | #include <com/sun/star/embed/XLinkageSupport.hpp> |
27 | | #include <com/sun/star/embed/XTransactedObject.hpp> |
28 | | #include <com/sun/star/embed/XOptimizedStorage.hpp> |
29 | | #include <com/sun/star/embed/EntryInitModes.hpp> |
30 | | #include <com/sun/star/io/IOException.hpp> |
31 | | #include <com/sun/star/util/XModifiable.hpp> |
32 | | #include <com/sun/star/embed/EmbedStates.hpp> |
33 | | #include <com/sun/star/beans/XPropertySetInfo.hpp> |
34 | | #include <com/sun/star/beans/XPropertySet.hpp> |
35 | | #include <com/sun/star/embed/Aspects.hpp> |
36 | | #include <com/sun/star/embed/EmbedMisc.hpp> |
37 | | |
38 | | #include <comphelper/classids.hxx> |
39 | | #include <comphelper/mimeconfighelper.hxx> |
40 | | #include <comphelper/seqstream.hxx> |
41 | | #include <comphelper/processfactory.hxx> |
42 | | #include <comphelper/storagehelper.hxx> |
43 | | #include <comphelper/embeddedobjectcontainer.hxx> |
44 | | #include <comphelper/sequence.hxx> |
45 | | #include <comphelper/propertysequence.hxx> |
46 | | #include <comphelper/propertyvalue.hxx> |
47 | | #include <cppuhelper/weakref.hxx> |
48 | | #include <sal/log.hxx> |
49 | | #include <rtl/ref.hxx> |
50 | | |
51 | | #include <officecfg/Office/Common.hxx> |
52 | | |
53 | | #include <algorithm> |
54 | | #include <unordered_map> |
55 | | |
56 | | |
57 | | using namespace ::com::sun::star; |
58 | | |
59 | | namespace comphelper { |
60 | | |
61 | | typedef std::unordered_map<OUString, uno::Reference<embed::XEmbeddedObject>> EmbeddedObjectContainerNameMap; |
62 | | struct EmbedImpl |
63 | | { |
64 | | // TODO/LATER: remove objects from temp. Container storage when object is disposed |
65 | | EmbeddedObjectContainerNameMap maNameToObjectMap; |
66 | | // to speed up lookup by Reference |
67 | | std::unordered_map<uno::Reference<embed::XEmbeddedObject>, OUString> maObjectToNameMap; |
68 | | uno::Reference < embed::XStorage > mxStorage; |
69 | | std::unique_ptr<EmbeddedObjectContainer> mpTempObjectContainer; |
70 | | uno::Reference < embed::XStorage > mxImageStorage; |
71 | | uno::WeakReference < uno::XInterface > m_xModel; |
72 | | |
73 | | bool mbOwnsStorage : 1; |
74 | | bool mbUserAllowsLinkUpdate : 1; |
75 | | |
76 | | const uno::Reference < embed::XStorage >& GetReplacements(); |
77 | | }; |
78 | | |
79 | | const uno::Reference < embed::XStorage >& EmbedImpl::GetReplacements() |
80 | 0 | { |
81 | 0 | if ( !mxImageStorage.is() ) |
82 | 0 | { |
83 | 0 | try |
84 | 0 | { |
85 | 0 | mxImageStorage = mxStorage->openStorageElement( |
86 | 0 | u"ObjectReplacements"_ustr, embed::ElementModes::READWRITE ); |
87 | 0 | } |
88 | 0 | catch (const uno::Exception&) |
89 | 0 | { |
90 | 0 | mxImageStorage = mxStorage->openStorageElement( |
91 | 0 | u"ObjectReplacements"_ustr, embed::ElementModes::READ ); |
92 | 0 | } |
93 | 0 | } |
94 | |
|
95 | 0 | if ( !mxImageStorage.is() ) |
96 | 0 | throw io::IOException(u"No ObjectReplacements"_ustr); |
97 | | |
98 | 0 | return mxImageStorage; |
99 | 0 | } |
100 | | |
101 | | EmbeddedObjectContainer::EmbeddedObjectContainer() |
102 | 11.6k | : pImpl(new EmbedImpl) |
103 | 11.6k | { |
104 | 11.6k | pImpl->mxStorage = ::comphelper::OStorageHelper::GetTemporaryStorage(); |
105 | 11.6k | pImpl->mbOwnsStorage = true; |
106 | 11.6k | pImpl->mbUserAllowsLinkUpdate = true; |
107 | 11.6k | pImpl->mpTempObjectContainer = nullptr; |
108 | 11.6k | } |
109 | | |
110 | | EmbeddedObjectContainer::EmbeddedObjectContainer( const uno::Reference < embed::XStorage >& rStor ) |
111 | 93 | : pImpl(new EmbedImpl) |
112 | 93 | { |
113 | 93 | pImpl->mxStorage = rStor; |
114 | 93 | pImpl->mbOwnsStorage = false; |
115 | 93 | pImpl->mbUserAllowsLinkUpdate = true; |
116 | 93 | pImpl->mpTempObjectContainer = nullptr; |
117 | 93 | } |
118 | | |
119 | | EmbeddedObjectContainer::EmbeddedObjectContainer( const uno::Reference < embed::XStorage >& rStor, const uno::Reference < uno::XInterface >& xModel ) |
120 | 32.2k | : pImpl(new EmbedImpl) |
121 | 32.2k | { |
122 | 32.2k | pImpl->mxStorage = rStor; |
123 | 32.2k | pImpl->mbOwnsStorage = false; |
124 | 32.2k | pImpl->mbUserAllowsLinkUpdate = true; |
125 | 32.2k | pImpl->mpTempObjectContainer = nullptr; |
126 | 32.2k | pImpl->m_xModel = xModel; |
127 | 32.2k | } |
128 | | |
129 | | void EmbeddedObjectContainer::SwitchPersistence( const uno::Reference < embed::XStorage >& rStor ) |
130 | 0 | { |
131 | 0 | ReleaseImageSubStorage(); |
132 | |
|
133 | 0 | if ( pImpl->mbOwnsStorage ) |
134 | 0 | pImpl->mxStorage->dispose(); |
135 | |
|
136 | 0 | pImpl->mxStorage = rStor; |
137 | 0 | pImpl->mbOwnsStorage = false; |
138 | 0 | } |
139 | | |
140 | | bool EmbeddedObjectContainer::CommitImageSubStorage() |
141 | 43.9k | { |
142 | 43.9k | if ( !pImpl->mxImageStorage ) |
143 | 43.9k | return true; |
144 | | |
145 | 0 | try |
146 | 0 | { |
147 | 0 | bool bReadOnlyMode = true; |
148 | 0 | uno::Reference < beans::XPropertySet > xSet(pImpl->mxImageStorage,uno::UNO_QUERY); |
149 | 0 | if ( xSet.is() ) |
150 | 0 | { |
151 | | // get the open mode from the parent storage |
152 | 0 | sal_Int32 nMode = 0; |
153 | 0 | uno::Any aAny = xSet->getPropertyValue(u"OpenMode"_ustr); |
154 | 0 | if ( aAny >>= nMode ) |
155 | 0 | bReadOnlyMode = !(nMode & embed::ElementModes::WRITE ); |
156 | 0 | } // if ( xSet.is() ) |
157 | 0 | if ( !bReadOnlyMode ) |
158 | 0 | { |
159 | 0 | uno::Reference< embed::XTransactedObject > xTransact( pImpl->mxImageStorage, uno::UNO_QUERY ); |
160 | 0 | if (xTransact) |
161 | 0 | xTransact->commit(); |
162 | 0 | } |
163 | 0 | } |
164 | 0 | catch (const uno::Exception&) |
165 | 0 | { |
166 | 0 | return false; |
167 | 0 | } |
168 | | |
169 | 0 | return true; |
170 | 0 | } |
171 | | |
172 | | void EmbeddedObjectContainer::ReleaseImageSubStorage() |
173 | 43.9k | { |
174 | 43.9k | CommitImageSubStorage(); |
175 | | |
176 | 43.9k | if ( pImpl->mxImageStorage.is() ) |
177 | 0 | { |
178 | 0 | try |
179 | 0 | { |
180 | 0 | pImpl->mxImageStorage->dispose(); |
181 | 0 | pImpl->mxImageStorage.clear(); |
182 | 0 | } |
183 | 0 | catch (const uno::Exception&) |
184 | 0 | { |
185 | 0 | SAL_WARN( "comphelper.container", "Problems releasing image substorage!" ); |
186 | 0 | } |
187 | 0 | } |
188 | 43.9k | } |
189 | | |
190 | | EmbeddedObjectContainer::~EmbeddedObjectContainer() |
191 | 43.9k | { |
192 | 43.9k | ReleaseImageSubStorage(); |
193 | | |
194 | 43.9k | if ( pImpl->mbOwnsStorage ) |
195 | 11.6k | pImpl->mxStorage->dispose(); |
196 | 43.9k | } |
197 | | |
198 | | void EmbeddedObjectContainer::CloseEmbeddedObjects() |
199 | 32.1k | { |
200 | 32.1k | for( const auto& rObj : pImpl->maNameToObjectMap ) |
201 | 10.8k | { |
202 | 10.8k | uno::Reference < embed::XEmbeddedObject > const & xClose = rObj.second; |
203 | 10.8k | if( xClose.is() ) |
204 | 0 | { |
205 | 0 | try |
206 | 0 | { |
207 | 0 | xClose->close( true ); |
208 | 0 | } |
209 | 0 | catch (const uno::Exception&) |
210 | 0 | { |
211 | 0 | } |
212 | 0 | } |
213 | 10.8k | } |
214 | 32.1k | } |
215 | | |
216 | | OUString EmbeddedObjectContainer::CreateUniqueObjectName() |
217 | 37.7k | { |
218 | 37.7k | OUString aStr; |
219 | 37.7k | sal_Int32 i=1; |
220 | 37.7k | do |
221 | 1.41M | { |
222 | 1.41M | aStr = "Object " + OUString::number( i++ ); |
223 | 1.41M | } |
224 | 1.41M | while( HasEmbeddedObject( aStr ) ); |
225 | | // TODO/LATER: should we consider deleted objects? |
226 | | |
227 | 37.7k | return aStr; |
228 | 37.7k | } |
229 | | |
230 | | uno::Sequence < OUString > EmbeddedObjectContainer::GetObjectNames() const |
231 | 594 | { |
232 | 594 | return comphelper::mapKeysToSequence(pImpl->maNameToObjectMap); |
233 | 594 | } |
234 | | |
235 | | bool EmbeddedObjectContainer::HasEmbeddedObjects() const |
236 | 0 | { |
237 | 0 | return !pImpl->maNameToObjectMap.empty(); |
238 | 0 | } |
239 | | |
240 | | bool EmbeddedObjectContainer::HasEmbeddedObject( const OUString& rName ) |
241 | 1.41M | { |
242 | 1.41M | if (pImpl->maNameToObjectMap.contains(rName)) |
243 | 1.38M | return true; |
244 | 37.7k | if (!pImpl->mxStorage.is()) |
245 | 1.26k | return false; |
246 | 36.5k | return pImpl->mxStorage->hasByName(rName); |
247 | 37.7k | } |
248 | | |
249 | | bool EmbeddedObjectContainer::HasEmbeddedObject( const uno::Reference < embed::XEmbeddedObject >& xObj ) const |
250 | 0 | { |
251 | 0 | return pImpl->maObjectToNameMap.contains(xObj); |
252 | 0 | } |
253 | | |
254 | | bool EmbeddedObjectContainer::HasInstantiatedEmbeddedObject( const OUString& rName ) |
255 | 197 | { |
256 | | // allows to detect whether the object was already instantiated |
257 | | // currently the filter instantiate it on loading, so this method allows |
258 | | // to avoid objects pointing to the same persistence |
259 | 197 | return pImpl->maNameToObjectMap.contains(rName); |
260 | 197 | } |
261 | | |
262 | | OUString EmbeddedObjectContainer::GetEmbeddedObjectName( const css::uno::Reference < css::embed::XEmbeddedObject >& xObj ) const |
263 | 0 | { |
264 | 0 | auto it = pImpl->maObjectToNameMap.find(xObj); |
265 | 0 | if (it == pImpl->maObjectToNameMap.end()) |
266 | 0 | { |
267 | 0 | SAL_WARN( "comphelper.container", "Unknown object!" ); |
268 | 0 | return OUString(); |
269 | 0 | } |
270 | 0 | return it->second; |
271 | 0 | } |
272 | | |
273 | | uno::Reference< embed::XEmbeddedObject> |
274 | | EmbeddedObjectContainer::GetEmbeddedObject( |
275 | | const OUString& rName, OUString const*const pBaseURL) |
276 | 15.6k | { |
277 | 15.6k | SAL_WARN_IF( rName.isEmpty(), "comphelper.container", "Empty object name!"); |
278 | | |
279 | 15.6k | uno::Reference < embed::XEmbeddedObject > xObj; |
280 | 15.6k | auto aIt = pImpl->maNameToObjectMap.find( rName ); |
281 | | |
282 | | #if OSL_DEBUG_LEVEL > 1 |
283 | | uno::Reference < container::XNameAccess > xAccess( pImpl->mxStorage, uno::UNO_QUERY ); |
284 | | uno::Sequence< OUString> aSeq = xAccess->getElementNames(); |
285 | | const OUString* pIter = aSeq.getConstArray(); |
286 | | const OUString* pEnd = pIter + aSeq.getLength(); |
287 | | for(;pIter != pEnd;++pIter) |
288 | | { |
289 | | (void)*pIter; |
290 | | } |
291 | | OSL_ENSURE( aIt != pImpl->maNameToObjectMap.end() || xAccess->hasByName(rName), "Could not return object!" ); |
292 | | #endif |
293 | | |
294 | | // check if object was already created |
295 | 15.6k | if ( aIt != pImpl->maNameToObjectMap.end() ) |
296 | 12.8k | xObj = (*aIt).second; |
297 | 2.84k | else |
298 | 2.84k | xObj = Get_Impl(rName, uno::Reference<embed::XEmbeddedObject>(), pBaseURL); |
299 | | |
300 | 15.6k | return xObj; |
301 | 15.6k | } |
302 | | |
303 | | uno::Reference<embed::XEmbeddedObject> EmbeddedObjectContainer::Get_Impl( |
304 | | const OUString& rName, |
305 | | const uno::Reference<embed::XEmbeddedObject>& xCopy, |
306 | | OUString const*const pBaseURL) |
307 | 2.84k | { |
308 | 2.84k | uno::Reference < embed::XEmbeddedObject > xObj; |
309 | 2.84k | try |
310 | 2.84k | { |
311 | | // create the object from the storage |
312 | 2.84k | uno::Reference < beans::XPropertySet > xSet( pImpl->mxStorage, uno::UNO_QUERY ); |
313 | 2.84k | bool bReadOnlyMode = true; |
314 | 2.84k | if ( xSet.is() ) |
315 | 1.58k | { |
316 | | // get the open mode from the parent storage |
317 | 1.58k | sal_Int32 nMode = 0; |
318 | 1.58k | uno::Any aAny = xSet->getPropertyValue(u"OpenMode"_ustr); |
319 | 1.58k | if ( aAny >>= nMode ) |
320 | 1.58k | bReadOnlyMode = !(nMode & embed::ElementModes::WRITE ); |
321 | 1.58k | } |
322 | | |
323 | | // object was not added until now - should happen only by calling this method from "inside" |
324 | | //TODO/LATER: it would be good to detect an error when an object should be created already, but isn't (not an "inside" call) |
325 | 2.84k | uno::Reference < embed::XEmbeddedObjectCreator > xFactory = embed::EmbeddedObjectCreator::create( ::comphelper::getProcessComponentContext() ); |
326 | 2.84k | uno::Sequence< beans::PropertyValue > aObjDescr(1 + (xCopy.is() ? 1 : 0) + (pBaseURL ? 1 : 0)); |
327 | 2.84k | auto itObjDescr = aObjDescr.getArray(); |
328 | 2.84k | itObjDescr->Name = "Parent"; |
329 | 2.84k | itObjDescr->Value <<= pImpl->m_xModel.get(); |
330 | 2.84k | if (pBaseURL) |
331 | 1.44k | { |
332 | 1.44k | ++itObjDescr; |
333 | 1.44k | itObjDescr->Name = "DefaultParentBaseURL"; |
334 | 1.44k | itObjDescr->Value <<= *pBaseURL; |
335 | 1.44k | } |
336 | 2.84k | if ( xCopy.is() ) |
337 | 0 | { |
338 | 0 | ++itObjDescr; |
339 | 0 | itObjDescr->Name = "CloneFrom"; |
340 | 0 | itObjDescr->Value <<= xCopy; |
341 | 0 | } |
342 | | |
343 | 2.84k | uno::Sequence< beans::PropertyValue > aMediaDescr{ comphelper::makePropertyValue( |
344 | 2.84k | u"ReadOnly"_ustr, bReadOnlyMode) }; |
345 | 2.84k | xObj.set( xFactory->createInstanceInitFromEntry( |
346 | 2.84k | pImpl->mxStorage, rName, |
347 | 2.84k | aMediaDescr, aObjDescr ), uno::UNO_QUERY ); |
348 | | |
349 | | // insert object into my list |
350 | 2.84k | AddEmbeddedObject( xObj, rName ); |
351 | 2.84k | } |
352 | 2.84k | catch (uno::Exception const& e) |
353 | 2.84k | { |
354 | 2.84k | SAL_WARN("comphelper.container", "EmbeddedObjectContainer::Get_Impl: exception caught: " << e); |
355 | 2.84k | } |
356 | | |
357 | 2.84k | return xObj; |
358 | 2.84k | } |
359 | | |
360 | | uno::Reference < embed::XEmbeddedObject > EmbeddedObjectContainer::CreateEmbeddedObject( |
361 | | const uno::Sequence < sal_Int8 >& rClassId, |
362 | | OUString& rNewName, |
363 | | std::optional<OUString> oDefaultParentBaseURL ) |
364 | 25.2k | { |
365 | 25.2k | if ( rNewName.isEmpty() ) |
366 | 25.2k | rNewName = CreateUniqueObjectName(); |
367 | | |
368 | 25.2k | SAL_WARN_IF( HasEmbeddedObject(rNewName), "comphelper.container", "Object to create already exists!"); |
369 | | |
370 | | // create object from classid by inserting it into storage |
371 | 25.2k | uno::Reference < embed::XEmbeddedObject > xObj; |
372 | 25.2k | try |
373 | 25.2k | { |
374 | 25.2k | uno::Reference < embed::XEmbeddedObjectCreator > xFactory = embed::EmbeddedObjectCreator::create( ::comphelper::getProcessComponentContext() ); |
375 | | |
376 | 25.2k | const size_t nArgs = oDefaultParentBaseURL.has_value() ? 2 : 1; |
377 | 25.2k | uno::Sequence< beans::PropertyValue > aObjDescr( nArgs ); |
378 | 25.2k | auto pObjDescr = aObjDescr.getArray(); |
379 | 25.2k | pObjDescr[0].Name = "Parent"; |
380 | 25.2k | pObjDescr[0].Value <<= pImpl->m_xModel.get(); |
381 | 25.2k | if (oDefaultParentBaseURL.has_value()) |
382 | 1.26k | { |
383 | 1.26k | pObjDescr[1].Name = "DefaultParentBaseURL"; |
384 | 1.26k | pObjDescr[1].Value <<= *oDefaultParentBaseURL; |
385 | 1.26k | } |
386 | 25.2k | xObj.set( xFactory->createInstanceInitNew( |
387 | 25.2k | rClassId, OUString(), pImpl->mxStorage, rNewName, |
388 | 25.2k | aObjDescr ), uno::UNO_QUERY ); |
389 | | |
390 | 25.2k | AddEmbeddedObject( xObj, rNewName ); |
391 | | |
392 | 25.2k | OSL_ENSURE( !xObj.is() || xObj->getCurrentState() != embed::EmbedStates::LOADED, |
393 | 25.2k | "A freshly create object should be running always!" ); |
394 | 25.2k | } |
395 | 25.2k | catch (uno::Exception const& e) |
396 | 25.2k | { |
397 | 25.2k | SAL_WARN("comphelper.container", "EmbeddedObjectContainer::CreateEmbeddedObject: exception caught: " << e); |
398 | 25.2k | } |
399 | | |
400 | 25.2k | return xObj; |
401 | 25.2k | } |
402 | | |
403 | | void EmbeddedObjectContainer::AddEmbeddedObject( |
404 | | const css::uno::Reference < css::embed::XEmbeddedObject >& xObj, const OUString& rName ) |
405 | 10.8k | { |
406 | | #if OSL_DEBUG_LEVEL > 1 |
407 | | SAL_WARN_IF( rName.isEmpty(), "comphelper.container", "Added object doesn't have a name!"); |
408 | | uno::Reference < container::XNameAccess > xAccess( pImpl->mxStorage, uno::UNO_QUERY ); |
409 | | uno::Reference < embed::XEmbedPersist > xEmb( xObj, uno::UNO_QUERY ); |
410 | | uno::Reference < embed::XLinkageSupport > xLink( xEmb, uno::UNO_QUERY ); |
411 | | // if the object has a persistence and the object is not a link than it must have persistence entry in the storage |
412 | | OSL_ENSURE( !( xEmb.is() && ( !xLink.is() || !xLink->isLink() ) ) || xAccess->hasByName(rName), |
413 | | "Added element not in storage!" ); |
414 | | #endif |
415 | | |
416 | | // remember object - it needs to be in storage already |
417 | 10.8k | auto aIt = pImpl->maNameToObjectMap.find( rName ); |
418 | 10.8k | OSL_ENSURE( aIt == pImpl->maNameToObjectMap.end(), "Element already inserted!" ); |
419 | 10.8k | pImpl->maNameToObjectMap[ rName ] = xObj; |
420 | 10.8k | pImpl->maObjectToNameMap[ xObj ] = rName; |
421 | 10.8k | uno::Reference < container::XChild > xChild( xObj, uno::UNO_QUERY ); |
422 | 10.8k | if ( xChild.is() && xChild->getParent() != pImpl->m_xModel.get() ) |
423 | 0 | xChild->setParent( pImpl->m_xModel.get() ); |
424 | | |
425 | | // look for object in temporary container |
426 | 10.8k | if ( !pImpl->mpTempObjectContainer ) |
427 | 10.8k | return; |
428 | | |
429 | 0 | auto& rObjectContainer = pImpl->mpTempObjectContainer->pImpl->maNameToObjectMap; |
430 | 0 | auto aIter = std::find_if(rObjectContainer.begin(), rObjectContainer.end(), |
431 | 0 | [&xObj](const EmbeddedObjectContainerNameMap::value_type& rEntry) { return rEntry.second == xObj; }); |
432 | 0 | if (aIter == rObjectContainer.end()) |
433 | 0 | return; |
434 | | |
435 | | // copy replacement image from temporary container (if there is any) |
436 | 0 | OUString aTempName = aIter->first; |
437 | 0 | OUString aMediaType; |
438 | 0 | uno::Reference < io::XInputStream > xStream = pImpl->mpTempObjectContainer->GetGraphicStream( xObj, &aMediaType ); |
439 | 0 | if ( xStream.is() ) |
440 | 0 | { |
441 | 0 | InsertGraphicStream( xStream, rName, aMediaType ); |
442 | 0 | xStream = nullptr; |
443 | 0 | pImpl->mpTempObjectContainer->RemoveGraphicStream( aTempName ); |
444 | 0 | } |
445 | | |
446 | | // remove object from storage of temporary container |
447 | 0 | uno::Reference < embed::XEmbedPersist > xPersist( xObj, uno::UNO_QUERY ); |
448 | 0 | if ( xPersist.is() ) |
449 | 0 | { |
450 | 0 | try |
451 | 0 | { |
452 | 0 | pImpl->mpTempObjectContainer->pImpl->mxStorage->removeElement( aTempName ); |
453 | 0 | } |
454 | 0 | catch (const uno::Exception&) |
455 | 0 | { |
456 | 0 | } |
457 | 0 | } |
458 | | |
459 | | // temp. container needs to forget the object |
460 | 0 | pImpl->mpTempObjectContainer->pImpl->maObjectToNameMap.erase( aIter->second ); |
461 | 0 | pImpl->mpTempObjectContainer->pImpl->maNameToObjectMap.erase( aIter ); |
462 | 0 | } |
463 | | |
464 | | bool EmbeddedObjectContainer::StoreEmbeddedObject( |
465 | | const uno::Reference < embed::XEmbeddedObject >& xObj, OUString& rName, bool bCopy, |
466 | | const OUString& rSrcShellID, const OUString& rDestShellID ) |
467 | 10.8k | { |
468 | 10.8k | uno::Reference < embed::XEmbedPersist > xPersist( xObj, uno::UNO_QUERY ); |
469 | 10.8k | if ( rName.isEmpty() ) |
470 | 10.8k | rName = CreateUniqueObjectName(); |
471 | | |
472 | | #if OSL_DEBUG_LEVEL > 1 |
473 | | uno::Reference < container::XNameAccess > xAccess( pImpl->mxStorage, uno::UNO_QUERY ); |
474 | | OSL_ENSURE( !xPersist.is() || !xAccess->hasByName(rName), "Inserting element already present in storage!" ); |
475 | | OSL_ENSURE( xPersist.is() || xObj->getCurrentState() == embed::EmbedStates::RUNNING, "Non persistent object inserted!"); |
476 | | #endif |
477 | | |
478 | | // insert objects' storage into the container storage (if object has one) |
479 | 10.8k | try |
480 | 10.8k | { |
481 | 10.8k | if ( xPersist.is() ) |
482 | 0 | { |
483 | 0 | uno::Sequence < beans::PropertyValue > aSeq; |
484 | 0 | auto aObjArgs(::comphelper::InitPropertySequence({ |
485 | 0 | { "SourceShellID", uno::Any(rSrcShellID) }, |
486 | 0 | { "DestinationShellID", uno::Any(rDestShellID) } |
487 | 0 | })); |
488 | 0 | if ( bCopy ) |
489 | 0 | { |
490 | 0 | xPersist->storeToEntry(pImpl->mxStorage, rName, aSeq, aObjArgs); |
491 | 0 | } |
492 | 0 | else |
493 | 0 | { |
494 | | //TODO/LATER: possible optimization, don't store immediately |
495 | | //xPersist->setPersistentEntry( pImpl->mxStorage, rName, embed::EntryInitModes::ENTRY_NO_INIT, aSeq, aSeq ); |
496 | 0 | xPersist->storeAsEntry( pImpl->mxStorage, rName, aSeq, aObjArgs ); |
497 | 0 | xPersist->saveCompleted( true ); |
498 | 0 | } |
499 | 0 | } |
500 | 10.8k | } |
501 | 10.8k | catch (uno::Exception const& e) |
502 | 10.8k | { |
503 | 0 | SAL_WARN("comphelper.container", "EmbeddedObjectContainer::StoreEmbeddedObject: exception caught: " << e); |
504 | | // TODO/LATER: better error recovery should keep storage intact |
505 | 0 | return false; |
506 | 0 | } |
507 | | |
508 | 10.8k | return true; |
509 | 10.8k | } |
510 | | bool EmbeddedObjectContainer::InsertEmbeddedObject( |
511 | | const uno::Reference < embed::XEmbeddedObject >& xObj, |
512 | | OUString& rName, |
513 | | OUString const* pTargetShellID ) |
514 | 10.8k | { |
515 | | // store it into the container storage |
516 | 10.8k | OUString sTargetShellID; |
517 | 10.8k | if (pTargetShellID) |
518 | 10.8k | sTargetShellID = *pTargetShellID; |
519 | 10.8k | if (StoreEmbeddedObject(xObj, rName, false, OUString(), sTargetShellID)) |
520 | 10.8k | { |
521 | | // remember object |
522 | 10.8k | AddEmbeddedObject( xObj, rName ); |
523 | 10.8k | return true; |
524 | 10.8k | } |
525 | 0 | else |
526 | 0 | return false; |
527 | 10.8k | } |
528 | | |
529 | | uno::Reference < embed::XEmbeddedObject > EmbeddedObjectContainer::InsertEmbeddedObject( |
530 | | const uno::Reference < io::XInputStream >& xStm, OUString& rNewName ) |
531 | 0 | { |
532 | 0 | if ( rNewName.isEmpty() ) |
533 | 0 | rNewName = CreateUniqueObjectName(); |
534 | | |
535 | | // store it into the container storage |
536 | 0 | bool bIsStorage = false; |
537 | 0 | try |
538 | 0 | { |
539 | | // first try storage persistence |
540 | 0 | uno::Reference < embed::XStorage > xStore = ::comphelper::OStorageHelper::GetStorageFromInputStream( xStm ); |
541 | | |
542 | | // storage was created from stream successfully |
543 | 0 | bIsStorage = true; |
544 | |
|
545 | 0 | uno::Reference < embed::XStorage > xNewStore = pImpl->mxStorage->openStorageElement( rNewName, embed::ElementModes::READWRITE ); |
546 | 0 | xStore->copyToStorage( xNewStore ); |
547 | 0 | } |
548 | 0 | catch (const uno::Exception&) |
549 | 0 | { |
550 | 0 | if ( bIsStorage ) |
551 | | // it is storage persistence, but opening of new substorage or copying to it failed |
552 | 0 | return uno::Reference < embed::XEmbeddedObject >(); |
553 | | |
554 | | // stream didn't contain a storage, now try stream persistence |
555 | 0 | try |
556 | 0 | { |
557 | 0 | uno::Reference < io::XStream > xNewStream = pImpl->mxStorage->openStreamElement( rNewName, embed::ElementModes::READWRITE ); |
558 | 0 | ::comphelper::OStorageHelper::CopyInputToOutput( xStm, xNewStream->getOutputStream() ); |
559 | | |
560 | | // No mediatype is provided so the default for OLE objects value is used |
561 | | // it is correct so for now, but what if somebody introduces a new stream based embedded object? |
562 | | // Probably introducing of such an object must be restricted ( a storage must be used! ). |
563 | 0 | uno::Reference< beans::XPropertySet > xProps( xNewStream, uno::UNO_QUERY_THROW ); |
564 | 0 | xProps->setPropertyValue(u"MediaType"_ustr, |
565 | 0 | uno::Any( u"application/vnd.sun.star.oleobject"_ustr ) ); |
566 | 0 | } |
567 | 0 | catch (uno::Exception const& e) |
568 | 0 | { |
569 | | // complete disaster! |
570 | 0 | SAL_WARN("comphelper.container", "EmbeddedObjectContainer::InsertEmbeddedObject: exception caught: " << e); |
571 | 0 | return uno::Reference < embed::XEmbeddedObject >(); |
572 | 0 | } |
573 | 0 | } |
574 | | |
575 | | // stream was copied into the container storage in either way, now try to open something form it |
576 | 0 | uno::Reference < embed::XEmbeddedObject > xRet = GetEmbeddedObject( rNewName ); |
577 | 0 | try |
578 | 0 | { |
579 | 0 | if ( !xRet.is() ) |
580 | | // no object could be created, so withdraw insertion |
581 | 0 | pImpl->mxStorage->removeElement( rNewName ); |
582 | 0 | } |
583 | 0 | catch (const uno::Exception&) |
584 | 0 | { |
585 | 0 | } |
586 | |
|
587 | 0 | return xRet; |
588 | 0 | } |
589 | | |
590 | | uno::Reference < embed::XEmbeddedObject > EmbeddedObjectContainer::InsertEmbeddedObject( |
591 | | const css::uno::Sequence < css::beans::PropertyValue >& aMedium, |
592 | | OUString& rNewName, OUString const* pBaseURL ) |
593 | 144 | { |
594 | 144 | if ( rNewName.isEmpty() ) |
595 | 0 | rNewName = CreateUniqueObjectName(); |
596 | | |
597 | 144 | uno::Reference < embed::XEmbeddedObject > xObj; |
598 | 144 | try |
599 | 144 | { |
600 | 144 | uno::Reference < embed::XEmbeddedObjectCreator > xFactory = embed::EmbeddedObjectCreator::create( ::comphelper::getProcessComponentContext() ); |
601 | 144 | uno::Sequence< beans::PropertyValue > aObjDescr(pBaseURL ? 2 : 1); |
602 | 144 | auto pObjDescr = aObjDescr.getArray(); |
603 | 144 | pObjDescr[0].Name = "Parent"; |
604 | 144 | pObjDescr[0].Value <<= pImpl->m_xModel.get(); |
605 | 144 | if (pBaseURL) |
606 | 0 | { |
607 | 0 | pObjDescr[1].Name = "DefaultParentBaseURL"; |
608 | 0 | pObjDescr[1].Value <<= *pBaseURL; |
609 | 0 | } |
610 | 144 | xObj.set( xFactory->createInstanceInitFromMediaDescriptor( |
611 | 144 | pImpl->mxStorage, rNewName, aMedium, aObjDescr ), uno::UNO_QUERY ); |
612 | 144 | uno::Reference < embed::XEmbedPersist > xPersist( xObj, uno::UNO_QUERY ); |
613 | | |
614 | 144 | OSL_ENSURE( !xObj.is() || xObj->getCurrentState() != embed::EmbedStates::LOADED, |
615 | 144 | "A freshly create object should be running always!" ); |
616 | | |
617 | | // possible optimization: store later! |
618 | 144 | if ( xPersist.is()) |
619 | 0 | xPersist->storeOwn(); |
620 | | |
621 | 144 | AddEmbeddedObject( xObj, rNewName ); |
622 | 144 | } |
623 | 144 | catch (const uno::Exception&) |
624 | 144 | { |
625 | 144 | } |
626 | | |
627 | 144 | return xObj; |
628 | 144 | } |
629 | | |
630 | | uno::Reference < embed::XEmbeddedObject > EmbeddedObjectContainer::InsertEmbeddedLink( |
631 | | const css::uno::Sequence < css::beans::PropertyValue >& aMedium, |
632 | | OUString& rNewName ) |
633 | 0 | { |
634 | 0 | if ( rNewName.isEmpty() ) |
635 | 0 | rNewName = CreateUniqueObjectName(); |
636 | |
|
637 | 0 | uno::Reference < embed::XEmbeddedObject > xObj; |
638 | 0 | try |
639 | 0 | { |
640 | 0 | uno::Reference < embed::XEmbeddedObjectCreator > xFactory = embed::EmbeddedObjectCreator::create(::comphelper::getProcessComponentContext()); |
641 | 0 | uno::Sequence< beans::PropertyValue > aObjDescr{ comphelper::makePropertyValue( |
642 | 0 | u"Parent"_ustr, pImpl->m_xModel.get()) }; |
643 | 0 | xObj.set( xFactory->createInstanceLink( pImpl->mxStorage, rNewName, aMedium, aObjDescr ), uno::UNO_QUERY ); |
644 | |
|
645 | 0 | uno::Reference < embed::XEmbedPersist > xPersist( xObj, uno::UNO_QUERY ); |
646 | |
|
647 | 0 | OSL_ENSURE( !xObj.is() || xObj->getCurrentState() != embed::EmbedStates::LOADED, |
648 | 0 | "A freshly create object should be running always!" ); |
649 | | |
650 | | // possible optimization: store later! |
651 | 0 | if ( xPersist.is()) |
652 | 0 | xPersist->storeOwn(); |
653 | |
|
654 | 0 | AddEmbeddedObject( xObj, rNewName ); |
655 | 0 | } |
656 | 0 | catch (uno::Exception const& e) |
657 | 0 | { |
658 | 0 | SAL_WARN("comphelper.container", "EmbeddedObjectContainer::InsertEmbeddedLink: " |
659 | 0 | "exception caught: " << e); |
660 | 0 | } |
661 | | |
662 | 0 | return xObj; |
663 | 0 | } |
664 | | |
665 | | bool EmbeddedObjectContainer::TryToCopyGraphReplacement( EmbeddedObjectContainer& rSrc, |
666 | | const OUString& aOrigName, |
667 | | const OUString& aTargetName ) |
668 | 0 | { |
669 | 0 | bool bResult = false; |
670 | |
|
671 | 0 | if ( ( &rSrc != this || aOrigName != aTargetName ) && !aOrigName.isEmpty() && !aTargetName.isEmpty() ) |
672 | 0 | { |
673 | 0 | OUString aMediaType; |
674 | 0 | uno::Reference < io::XInputStream > xGrStream = rSrc.GetGraphicStream( aOrigName, &aMediaType ); |
675 | 0 | if ( xGrStream.is() ) |
676 | 0 | bResult = InsertGraphicStream( xGrStream, aTargetName, aMediaType ); |
677 | 0 | } |
678 | |
|
679 | 0 | return bResult; |
680 | 0 | } |
681 | | |
682 | | uno::Reference < embed::XEmbeddedObject > EmbeddedObjectContainer::CopyAndGetEmbeddedObject( |
683 | | EmbeddedObjectContainer& rSrc, const uno::Reference <embed::XEmbeddedObject>& xObj, OUString& rName, |
684 | | const OUString& rSrcShellID, const OUString& rDestShellID ) |
685 | 363 | { |
686 | 363 | uno::Reference< embed::XEmbeddedObject > xResult; |
687 | | |
688 | | // TODO/LATER: For now only objects that implement XEmbedPersist have a replacement image, it might change in future |
689 | | // do an incompatible change so that object name is provided in all the move and copy methods |
690 | 363 | OUString aOrigName; |
691 | 363 | try |
692 | 363 | { |
693 | 363 | uno::Reference < embed::XEmbedPersist > xPersist( xObj, uno::UNO_QUERY ); |
694 | 363 | if (xPersist) |
695 | 0 | aOrigName = xPersist->getEntryName(); |
696 | 363 | } |
697 | 363 | catch (const uno::Exception&) |
698 | 363 | { |
699 | 0 | } |
700 | | |
701 | 363 | if ( rName.isEmpty() ) |
702 | 363 | rName = CreateUniqueObjectName(); |
703 | | |
704 | | // objects without persistence are not really stored by the method |
705 | 363 | if (xObj.is() && StoreEmbeddedObject(xObj, rName, true, rSrcShellID, rDestShellID)) |
706 | 0 | { |
707 | 0 | SAL_INFO_IF(rDestShellID.isEmpty(), "comphelper.container", |
708 | 0 | "SfxObjectShell with no base URL?"); // every shell has a base URL, except the clipboard SwDocShell |
709 | 0 | xResult = Get_Impl(rName, xObj, &rDestShellID); |
710 | 0 | if ( !xResult.is() ) |
711 | 0 | { |
712 | | // this is a case when object has no real persistence |
713 | | // in such cases a new object should be explicitly created and initialized with the data of the old one |
714 | 0 | try |
715 | 0 | { |
716 | 0 | uno::Reference< embed::XLinkageSupport > xOrigLinkage( xObj, uno::UNO_QUERY ); |
717 | 0 | if ( xOrigLinkage.is() && xOrigLinkage->isLink() ) |
718 | 0 | { |
719 | | // this is an OOo link, it has no persistence |
720 | 0 | OUString aURL = xOrigLinkage->getLinkURL(); |
721 | 0 | if ( aURL.isEmpty() ) |
722 | 0 | throw uno::RuntimeException(u"URL of the linked object is empty"_ustr); |
723 | | |
724 | | // create new linked object from the URL the link is based on |
725 | 0 | uno::Reference < embed::XEmbeddedObjectCreator > xCreator = |
726 | 0 | embed::EmbeddedObjectCreator::create( ::comphelper::getProcessComponentContext() ); |
727 | |
|
728 | 0 | uno::Sequence< beans::PropertyValue > aMediaDescr{ comphelper::makePropertyValue( |
729 | 0 | u"URL"_ustr, aURL) }; |
730 | 0 | uno::Sequence< beans::PropertyValue > aObjDescr{ comphelper::makePropertyValue( |
731 | 0 | u"Parent"_ustr, pImpl->m_xModel.get()) }; |
732 | 0 | xResult.set(xCreator->createInstanceLink( |
733 | 0 | pImpl->mxStorage, |
734 | 0 | rName, |
735 | 0 | aMediaDescr, |
736 | 0 | aObjDescr ), |
737 | 0 | uno::UNO_QUERY_THROW ); |
738 | 0 | } |
739 | 0 | else |
740 | 0 | { |
741 | | // the component is required for copying of this object |
742 | 0 | if ( xObj->getCurrentState() == embed::EmbedStates::LOADED ) |
743 | 0 | xObj->changeState( embed::EmbedStates::RUNNING ); |
744 | | |
745 | | // this must be an object based on properties, otherwise we can not copy it currently |
746 | 0 | uno::Reference< beans::XPropertySet > xOrigProps( xObj->getComponent(), uno::UNO_QUERY_THROW ); |
747 | | |
748 | | // use object class ID to create a new one and transfer all the properties |
749 | 0 | uno::Reference < embed::XEmbeddedObjectCreator > xCreator = |
750 | 0 | embed::EmbeddedObjectCreator::create( ::comphelper::getProcessComponentContext() ); |
751 | |
|
752 | 0 | uno::Sequence< beans::PropertyValue > aObjDescr{ comphelper::makePropertyValue( |
753 | 0 | u"Parent"_ustr, pImpl->m_xModel.get()) }; |
754 | 0 | xResult.set(xCreator->createInstanceInitNew( |
755 | 0 | xObj->getClassID(), |
756 | 0 | xObj->getClassName(), |
757 | 0 | pImpl->mxStorage, |
758 | 0 | rName, |
759 | 0 | aObjDescr ), |
760 | 0 | uno::UNO_QUERY_THROW ); |
761 | |
|
762 | 0 | if ( xResult->getCurrentState() == embed::EmbedStates::LOADED ) |
763 | 0 | xResult->changeState( embed::EmbedStates::RUNNING ); |
764 | |
|
765 | 0 | uno::Reference< beans::XPropertySet > xTargetProps( xResult->getComponent(), uno::UNO_QUERY_THROW ); |
766 | | |
767 | | // copy all the properties from xOrigProps to xTargetProps |
768 | 0 | uno::Reference< beans::XPropertySetInfo > xOrigInfo = xOrigProps->getPropertySetInfo(); |
769 | 0 | if ( !xOrigInfo.is() ) |
770 | 0 | throw uno::RuntimeException(u"Object has no properties"_ustr); |
771 | | |
772 | 0 | const uno::Sequence< beans::Property > aPropertiesList = xOrigInfo->getProperties(); |
773 | 0 | for ( const auto & p : aPropertiesList ) |
774 | 0 | { |
775 | 0 | try |
776 | 0 | { |
777 | 0 | xTargetProps->setPropertyValue( |
778 | 0 | p.Name, |
779 | 0 | xOrigProps->getPropertyValue( p.Name ) ); |
780 | 0 | } |
781 | 0 | catch (const beans::PropertyVetoException&) |
782 | 0 | { |
783 | | // impossibility to copy readonly property is not treated as an error for now |
784 | | // but the assertion is helpful to detect such scenarios and review them |
785 | 0 | SAL_WARN( "comphelper.container", "Could not copy readonly property!" ); |
786 | 0 | } |
787 | 0 | } |
788 | 0 | } |
789 | | |
790 | 0 | if ( xResult.is() ) |
791 | 0 | AddEmbeddedObject( xResult, rName ); |
792 | 0 | } |
793 | 0 | catch (const uno::Exception&) |
794 | 0 | { |
795 | 0 | if ( xResult.is() ) |
796 | 0 | { |
797 | 0 | try |
798 | 0 | { |
799 | 0 | xResult->close( true ); |
800 | 0 | } |
801 | 0 | catch (const uno::Exception&) |
802 | 0 | { |
803 | 0 | } |
804 | 0 | xResult.clear(); |
805 | 0 | } |
806 | 0 | } |
807 | 0 | } |
808 | 0 | } |
809 | | |
810 | 363 | SAL_WARN_IF( !xResult.is(), "comphelper.container", "Can not copy embedded object that has no persistence!" ); |
811 | | |
812 | 363 | if ( xResult.is() ) |
813 | 0 | { |
814 | | // the object is successfully copied, try to copy graphical replacement |
815 | 0 | if ( !aOrigName.isEmpty() ) |
816 | 0 | TryToCopyGraphReplacement( rSrc, aOrigName, rName ); |
817 | | |
818 | | // the object might need the size to be set |
819 | 0 | try |
820 | 0 | { |
821 | 0 | if ( xResult->getStatus( embed::Aspects::MSOLE_CONTENT ) & embed::EmbedMisc::EMBED_NEEDSSIZEONLOAD ) |
822 | 0 | xResult->setVisualAreaSize( embed::Aspects::MSOLE_CONTENT, |
823 | 0 | xObj->getVisualAreaSize( embed::Aspects::MSOLE_CONTENT ) ); |
824 | 0 | } |
825 | 0 | catch (const uno::Exception&) |
826 | 0 | { |
827 | 0 | } |
828 | 0 | } |
829 | | |
830 | 363 | return xResult; |
831 | 363 | } |
832 | | |
833 | | // #i119941, bKeepToTempStorage: use to specify whether store the removed object to temporary storage+ |
834 | | void EmbeddedObjectContainer::RemoveEmbeddedObject( const OUString& rName, bool bKeepToTempStorage ) |
835 | 558 | { |
836 | 558 | uno::Reference < embed::XEmbeddedObject > xObj = GetEmbeddedObject( rName ); |
837 | 558 | if ( xObj.is() ) |
838 | 0 | RemoveEmbeddedObject( xObj, bKeepToTempStorage ); |
839 | 558 | } |
840 | | |
841 | | bool EmbeddedObjectContainer::MoveEmbeddedObject( const OUString& rName, EmbeddedObjectContainer& rCnt ) |
842 | 0 | { |
843 | | // find object entry |
844 | 0 | auto aIt2 = rCnt.pImpl->maNameToObjectMap.find( rName ); |
845 | 0 | OSL_ENSURE( aIt2 == rCnt.pImpl->maNameToObjectMap.end(), "Object does already exist in target container!" ); |
846 | |
|
847 | 0 | if ( aIt2 != rCnt.pImpl->maNameToObjectMap.end() ) |
848 | 0 | return false; |
849 | | |
850 | 0 | uno::Reference < embed::XEmbeddedObject > xObj; |
851 | 0 | auto aIt = pImpl->maNameToObjectMap.find( rName ); |
852 | 0 | if ( aIt != pImpl->maNameToObjectMap.end() ) |
853 | 0 | { |
854 | 0 | xObj = (*aIt).second; |
855 | 0 | try |
856 | 0 | { |
857 | 0 | if ( xObj.is() ) |
858 | 0 | { |
859 | | // move object |
860 | 0 | OUString aName( rName ); |
861 | 0 | rCnt.InsertEmbeddedObject( xObj, aName ); |
862 | 0 | pImpl->maObjectToNameMap.erase( aIt->second ); |
863 | 0 | pImpl->maNameToObjectMap.erase( aIt ); |
864 | 0 | uno::Reference < embed::XEmbedPersist > xPersist( xObj, uno::UNO_QUERY ); |
865 | 0 | if ( xPersist.is() ) |
866 | 0 | pImpl->mxStorage->removeElement( rName ); |
867 | 0 | } |
868 | 0 | else |
869 | 0 | { |
870 | | // copy storages; object *must* have persistence! |
871 | 0 | uno::Reference < embed::XStorage > xOld = pImpl->mxStorage->openStorageElement( rName, embed::ElementModes::READ ); |
872 | 0 | uno::Reference < embed::XStorage > xNew = rCnt.pImpl->mxStorage->openStorageElement( rName, embed::ElementModes::READWRITE ); |
873 | 0 | xOld->copyToStorage( xNew ); |
874 | 0 | } |
875 | |
|
876 | 0 | rCnt.TryToCopyGraphReplacement( *this, rName, rName ); |
877 | | // RemoveGraphicStream( rName ); |
878 | |
|
879 | 0 | return true; |
880 | 0 | } |
881 | 0 | catch (const uno::Exception&) |
882 | 0 | { |
883 | 0 | SAL_WARN( "comphelper.container", "Could not move object!"); |
884 | 0 | return false; |
885 | 0 | } |
886 | |
|
887 | 0 | } |
888 | 0 | else |
889 | 0 | SAL_WARN( "comphelper.container", "Unknown object!"); |
890 | 0 | return false; |
891 | 0 | } |
892 | | |
893 | | // #i119941, bKeepToTempStorage: use to specify whether store the removed object to temporary storage+ |
894 | | bool EmbeddedObjectContainer::RemoveEmbeddedObject( |
895 | | const uno::Reference < embed::XEmbeddedObject >& xObj, bool bKeepToTempStorage ) |
896 | 0 | { |
897 | 0 | uno::Reference < embed::XEmbedPersist > xPersist( xObj, uno::UNO_QUERY ); |
898 | 0 | OUString aName; |
899 | 0 | if ( xPersist.is() ) |
900 | 0 | aName = xPersist->getEntryName(); |
901 | |
|
902 | | #if OSL_DEBUG_LEVEL > 1 |
903 | | uno::Reference < container::XNameAccess > xAccess( pImpl->mxStorage, uno::UNO_QUERY ); |
904 | | uno::Reference < embed::XLinkageSupport > xLink( xPersist, uno::UNO_QUERY ); |
905 | | sal_Bool bIsNotEmbedded = !xPersist.is() || ( xLink.is() && xLink->isLink() ); |
906 | | |
907 | | // if the object has a persistence and the object is not a link than it must have persistence entry in the storage |
908 | | OSL_ENSURE( bIsNotEmbedded || xAccess->hasByName(aName), "Removing element not present in storage!" ); |
909 | | #endif |
910 | | |
911 | | // somebody still needs the object, so we must assign a temporary persistence |
912 | 0 | try |
913 | 0 | { |
914 | 0 | if ( xPersist.is() && bKeepToTempStorage ) // #i119941 |
915 | 0 | { |
916 | |
|
917 | 0 | if ( !pImpl->mpTempObjectContainer ) |
918 | 0 | { |
919 | 0 | pImpl->mpTempObjectContainer = std::make_unique<EmbeddedObjectContainer>(); |
920 | 0 | try |
921 | 0 | { |
922 | | // TODO/LATER: in future probably the temporary container will have two storages ( of two formats ) |
923 | | // the media type will be provided with object insertion |
924 | 0 | OUString aOrigStorMediaType; |
925 | 0 | uno::Reference< beans::XPropertySet > xStorProps( pImpl->mxStorage, uno::UNO_QUERY_THROW ); |
926 | 0 | static constexpr OUString s_sMediaType(u"MediaType"_ustr); |
927 | 0 | xStorProps->getPropertyValue( s_sMediaType ) >>= aOrigStorMediaType; |
928 | |
|
929 | 0 | SAL_WARN_IF( aOrigStorMediaType.isEmpty(), "comphelper.container", "No valuable media type in the storage!" ); |
930 | | |
931 | 0 | uno::Reference< beans::XPropertySet > xTargetStorProps( |
932 | 0 | pImpl->mpTempObjectContainer->pImpl->mxStorage, |
933 | 0 | uno::UNO_QUERY_THROW ); |
934 | 0 | xTargetStorProps->setPropertyValue( s_sMediaType,uno::Any( aOrigStorMediaType ) ); |
935 | 0 | } |
936 | 0 | catch (const uno::Exception&) |
937 | 0 | { |
938 | 0 | SAL_WARN( "comphelper.container", "Can not set the new media type to a storage!" ); |
939 | 0 | } |
940 | 0 | } |
941 | | |
942 | 0 | OUString aTempName, aMediaType; |
943 | | /* Do not create a new name for a removed object, in the pImpl->mpTempObjectContainer, |
944 | | because the original m_aEntryName of xObj will be overwritten by InsertEmbeddedObject(), |
945 | | so uno::Reference < embed::XEmbeddedObject >& xObj will misbehave in |
946 | | EmbeddedObjectContainer::StoreAsChildren and SfxObjectShell::SaveCompletedChildren |
947 | | and will throw an exception because of objects with the same names! */ |
948 | 0 | if( !pImpl->mpTempObjectContainer->HasEmbeddedObject(aName) ) |
949 | 0 | aTempName = aName; |
950 | |
|
951 | 0 | pImpl->mpTempObjectContainer->InsertEmbeddedObject( xObj, aTempName ); |
952 | |
|
953 | 0 | uno::Reference < io::XInputStream > xStream = GetGraphicStream( xObj, &aMediaType ); |
954 | 0 | if ( xStream.is() ) |
955 | 0 | pImpl->mpTempObjectContainer->InsertGraphicStream( xStream, aTempName, aMediaType ); |
956 | | |
957 | | // object is stored, so at least it can be set to loaded state |
958 | 0 | xObj->changeState( embed::EmbedStates::LOADED ); |
959 | 0 | } |
960 | 0 | else |
961 | | // objects without persistence need to stay in running state if they shall not be closed |
962 | 0 | xObj->changeState( embed::EmbedStates::RUNNING ); |
963 | 0 | } |
964 | 0 | catch (const uno::Exception&) |
965 | 0 | { |
966 | 0 | return false; |
967 | 0 | } |
968 | | |
969 | 0 | auto aIter = std::find_if(pImpl->maNameToObjectMap.begin(), pImpl->maNameToObjectMap.end(), |
970 | 0 | [&xObj](const EmbeddedObjectContainerNameMap::value_type& rEntry) { return rEntry.second == xObj; }); |
971 | 0 | if (aIter != pImpl->maNameToObjectMap.end()) |
972 | 0 | { |
973 | 0 | pImpl->maObjectToNameMap.erase( aIter->second ); |
974 | 0 | pImpl->maNameToObjectMap.erase( aIter ); |
975 | 0 | uno::Reference < container::XChild > xChild( xObj, uno::UNO_QUERY ); |
976 | 0 | if ( xChild.is() ) |
977 | 0 | xChild->setParent( uno::Reference < uno::XInterface >() ); |
978 | 0 | } |
979 | 0 | else |
980 | 0 | SAL_WARN( "comphelper.container", "Object not found for removal!" ); |
981 | | |
982 | 0 | if ( !xPersist || !bKeepToTempStorage ) // #i119941# |
983 | 0 | return true; |
984 | | |
985 | | // remove replacement image (if there is one) |
986 | 0 | RemoveGraphicStream( aName ); |
987 | | |
988 | | // now it's time to remove the storage from the container storage |
989 | 0 | try |
990 | 0 | { |
991 | | #if OSL_DEBUG_LEVEL > 1 |
992 | | // if the object has a persistence and the object is not a link than it must have persistence entry in storage |
993 | | OSL_ENSURE( bIsNotEmbedded || pImpl->mxStorage->hasByName( aName ), "The object has no persistence entry in the storage!" ); |
994 | | #endif |
995 | 0 | if ( xPersist.is() && pImpl->mxStorage->hasByName( aName ) ) |
996 | 0 | pImpl->mxStorage->removeElement( aName ); |
997 | 0 | } |
998 | 0 | catch (const uno::Exception&) |
999 | 0 | { |
1000 | 0 | SAL_WARN( "comphelper.container", "Failed to remove object from storage!" ); |
1001 | 0 | return false; |
1002 | 0 | } |
1003 | | |
1004 | 0 | return true; |
1005 | 0 | } |
1006 | | |
1007 | | void EmbeddedObjectContainer::CloseEmbeddedObject( const uno::Reference < embed::XEmbeddedObject >& xObj ) |
1008 | 0 | { |
1009 | | // disconnect the object from the container and close it if possible |
1010 | |
|
1011 | 0 | auto aIter = std::find_if(pImpl->maNameToObjectMap.begin(), pImpl->maNameToObjectMap.end(), |
1012 | 0 | [&xObj](const EmbeddedObjectContainerNameMap::value_type& rEntry) { return rEntry.second == xObj; }); |
1013 | 0 | if (aIter == pImpl->maNameToObjectMap.end()) |
1014 | 0 | return; |
1015 | | |
1016 | 0 | pImpl->maObjectToNameMap.erase( aIter->second ); |
1017 | 0 | pImpl->maNameToObjectMap.erase( aIter ); |
1018 | |
|
1019 | 0 | try |
1020 | 0 | { |
1021 | 0 | xObj->close( true ); |
1022 | 0 | } |
1023 | 0 | catch (const uno::Exception&) |
1024 | 0 | { |
1025 | | // it is no problem if the object is already closed |
1026 | | // TODO/LATER: what if the object can not be closed? |
1027 | 0 | } |
1028 | 0 | } |
1029 | | |
1030 | | uno::Reference < io::XInputStream > EmbeddedObjectContainer::GetGraphicStream( const OUString& aName, OUString* pMediaType ) |
1031 | 0 | { |
1032 | 0 | uno::Reference < io::XInputStream > xStream; |
1033 | |
|
1034 | 0 | SAL_WARN_IF( aName.isEmpty(), "comphelper.container", "Retrieving graphic for unknown object!" ); |
1035 | 0 | if ( !aName.isEmpty() ) |
1036 | 0 | { |
1037 | 0 | try |
1038 | 0 | { |
1039 | 0 | uno::Reference < embed::XStorage > xReplacements = pImpl->GetReplacements(); |
1040 | 0 | uno::Reference < io::XStream > xGraphicStream = xReplacements->openStreamElement( aName, embed::ElementModes::READ ); |
1041 | 0 | xStream = xGraphicStream->getInputStream(); |
1042 | 0 | if ( pMediaType ) |
1043 | 0 | { |
1044 | 0 | uno::Reference < beans::XPropertySet > xSet( xStream, uno::UNO_QUERY ); |
1045 | 0 | if ( xSet.is() ) |
1046 | 0 | { |
1047 | 0 | uno::Any aAny = xSet->getPropertyValue(u"MediaType"_ustr); |
1048 | 0 | aAny >>= *pMediaType; |
1049 | 0 | } |
1050 | 0 | } |
1051 | 0 | } |
1052 | 0 | catch (uno::Exception const& e) |
1053 | 0 | { |
1054 | 0 | SAL_INFO("comphelper.container", |
1055 | 0 | "EmbeddedObjectContainer::GetGraphicStream(): " << e); |
1056 | 0 | } |
1057 | 0 | } |
1058 | | |
1059 | 0 | return xStream; |
1060 | 0 | } |
1061 | | |
1062 | | uno::Reference < io::XInputStream > EmbeddedObjectContainer::GetGraphicStream( const css::uno::Reference < css::embed::XEmbeddedObject >& xObj, OUString* pMediaType ) |
1063 | 0 | { |
1064 | | // try to load it from the container storage |
1065 | 0 | return GetGraphicStream( GetEmbeddedObjectName( xObj ), pMediaType ); |
1066 | 0 | } |
1067 | | |
1068 | | bool EmbeddedObjectContainer::InsertGraphicStream( const css::uno::Reference < css::io::XInputStream >& rStream, const OUString& rObjectName, const OUString& rMediaType ) |
1069 | 0 | { |
1070 | 0 | try |
1071 | 0 | { |
1072 | 0 | uno::Reference < embed::XStorage > xReplacements = pImpl->GetReplacements(); |
1073 | | |
1074 | | // store it into the subfolder |
1075 | 0 | uno::Reference < io::XOutputStream > xOutStream; |
1076 | 0 | uno::Reference < io::XStream > xGraphicStream = xReplacements->openStreamElement( rObjectName, |
1077 | 0 | embed::ElementModes::READWRITE | embed::ElementModes::TRUNCATE ); |
1078 | 0 | xOutStream = xGraphicStream->getOutputStream(); |
1079 | 0 | ::comphelper::OStorageHelper::CopyInputToOutput( rStream, xOutStream ); |
1080 | 0 | xOutStream->flush(); |
1081 | |
|
1082 | 0 | uno::Reference< beans::XPropertySet > xPropSet( xGraphicStream, uno::UNO_QUERY ); |
1083 | 0 | if (xPropSet) |
1084 | 0 | { |
1085 | 0 | xPropSet->setPropertyValue(u"UseCommonStoragePasswordEncryption"_ustr, |
1086 | 0 | uno::Any( true ) ); |
1087 | 0 | xPropSet->setPropertyValue(u"MediaType"_ustr, uno::Any(rMediaType) ); |
1088 | |
|
1089 | 0 | xPropSet->setPropertyValue(u"Compressed"_ustr, |
1090 | 0 | uno::Any( true ) ); |
1091 | 0 | } |
1092 | 0 | } |
1093 | 0 | catch (const uno::Exception&) |
1094 | 0 | { |
1095 | 0 | return false; |
1096 | 0 | } |
1097 | | |
1098 | 0 | return true; |
1099 | 0 | } |
1100 | | |
1101 | | bool EmbeddedObjectContainer::InsertGraphicStreamDirectly( const css::uno::Reference < css::io::XInputStream >& rStream, const OUString& rObjectName, const OUString& rMediaType ) |
1102 | 0 | { |
1103 | 0 | try |
1104 | 0 | { |
1105 | 0 | uno::Reference < embed::XStorage > xReplacement = pImpl->GetReplacements(); |
1106 | 0 | uno::Reference < embed::XOptimizedStorage > xOptRepl( xReplacement, uno::UNO_QUERY_THROW ); |
1107 | | |
1108 | | // store it into the subfolder |
1109 | 0 | uno::Sequence< beans::PropertyValue > aProps{ |
1110 | 0 | comphelper::makePropertyValue(u"MediaType"_ustr, rMediaType), |
1111 | 0 | comphelper::makePropertyValue(u"UseCommonStoragePasswordEncryption"_ustr, true), |
1112 | 0 | comphelper::makePropertyValue(u"Compressed"_ustr, true) |
1113 | 0 | }; |
1114 | |
|
1115 | 0 | if ( xReplacement->hasByName( rObjectName ) ) |
1116 | 0 | xReplacement->removeElement( rObjectName ); |
1117 | |
|
1118 | 0 | xOptRepl->insertStreamElementDirect( rObjectName, rStream, aProps ); |
1119 | 0 | } |
1120 | 0 | catch (const uno::Exception&) |
1121 | 0 | { |
1122 | 0 | return false; |
1123 | 0 | } |
1124 | | |
1125 | 0 | return true; |
1126 | 0 | } |
1127 | | |
1128 | | |
1129 | | void EmbeddedObjectContainer::RemoveGraphicStream( const OUString& rObjectName ) |
1130 | 0 | { |
1131 | 0 | try |
1132 | 0 | { |
1133 | 0 | uno::Reference < embed::XStorage > xReplacements = pImpl->GetReplacements(); |
1134 | 0 | xReplacements->removeElement( rObjectName ); |
1135 | 0 | } |
1136 | 0 | catch (const uno::Exception&) |
1137 | 0 | { |
1138 | 0 | } |
1139 | 0 | } |
1140 | | namespace { |
1141 | | void InsertStreamIntoPicturesStorage_Impl( const uno::Reference< embed::XStorage >& xDocStor, |
1142 | | const uno::Reference< io::XInputStream >& xInStream, |
1143 | | const OUString& aStreamName ) |
1144 | 0 | { |
1145 | 0 | OSL_ENSURE( !aStreamName.isEmpty() && xInStream.is() && xDocStor.is(), "Misuse of the method!" ); |
1146 | |
|
1147 | 0 | try |
1148 | 0 | { |
1149 | 0 | uno::Reference< embed::XStorage > xPictures = xDocStor->openStorageElement( |
1150 | 0 | u"Pictures"_ustr, |
1151 | 0 | embed::ElementModes::READWRITE ); |
1152 | 0 | uno::Reference< io::XStream > xObjReplStr = xPictures->openStreamElement( |
1153 | 0 | aStreamName, |
1154 | 0 | embed::ElementModes::READWRITE | embed::ElementModes::TRUNCATE ); |
1155 | 0 | uno::Reference< io::XOutputStream > xOutStream( |
1156 | 0 | xObjReplStr->getInputStream(), uno::UNO_QUERY_THROW ); |
1157 | |
|
1158 | 0 | ::comphelper::OStorageHelper::CopyInputToOutput( xInStream, xOutStream ); |
1159 | 0 | xOutStream->closeOutput(); |
1160 | |
|
1161 | 0 | uno::Reference< embed::XTransactedObject > xTransact( xPictures, uno::UNO_QUERY ); |
1162 | 0 | if ( xTransact.is() ) |
1163 | 0 | xTransact->commit(); |
1164 | 0 | } |
1165 | 0 | catch (const uno::Exception&) |
1166 | 0 | { |
1167 | 0 | SAL_WARN( "comphelper.container", "The images storage is not available!" ); |
1168 | 0 | } |
1169 | 0 | } |
1170 | | |
1171 | | } |
1172 | | |
1173 | | static bool AlwaysStoreReplacementImages(const uno::Reference<embed::XEmbeddedObject>& xObj) |
1174 | 0 | { |
1175 | 0 | const auto clsid = xObj->getClassID(); |
1176 | 0 | if (clsid == MimeConfigurationHelper::GetSequenceClassID(SO3_SCH_CLASSID) |
1177 | 0 | || clsid == MimeConfigurationHelper::GetSequenceClassID(SO3_SM_CLASSID)) |
1178 | 0 | return false; |
1179 | 0 | return true; |
1180 | 0 | } |
1181 | | |
1182 | | bool EmbeddedObjectContainer::StoreAsChildren(bool _bOasisFormat,bool _bCreateEmbedded, bool _bAutoSaveEvent, |
1183 | | const uno::Reference < embed::XStorage >& _xStorage) |
1184 | 0 | { |
1185 | 0 | bool bResult = false; |
1186 | 0 | try |
1187 | 0 | { |
1188 | 0 | comphelper::EmbeddedObjectContainer aCnt( _xStorage ); |
1189 | 0 | for (auto& name : GetObjectNames()) |
1190 | 0 | { |
1191 | 0 | uno::Reference<embed::XEmbeddedObject> xObj = GetEmbeddedObject(name); |
1192 | 0 | SAL_WARN_IF( !xObj.is(), "comphelper.container", "An empty entry in the embedded objects list!" ); |
1193 | 0 | if ( xObj.is() ) |
1194 | 0 | { |
1195 | 0 | bool bSwitchBackToLoaded = false; |
1196 | 0 | uno::Reference< embed::XLinkageSupport > xLink( xObj, uno::UNO_QUERY ); |
1197 | |
|
1198 | 0 | uno::Reference < io::XInputStream > xStream; |
1199 | 0 | OUString aMediaType; |
1200 | 0 | if (officecfg::Office::Common::Save::Graphic::AddReplacementImages::get() |
1201 | 0 | || AlwaysStoreReplacementImages(xObj)) |
1202 | 0 | { |
1203 | 0 | sal_Int32 nCurState = xObj->getCurrentState(); |
1204 | 0 | if (nCurState == embed::EmbedStates::LOADED |
1205 | 0 | || nCurState == embed::EmbedStates::RUNNING) |
1206 | 0 | { |
1207 | | // means that the object is not active |
1208 | | // copy replacement image from old to new container |
1209 | 0 | xStream = GetGraphicStream(xObj, &aMediaType); |
1210 | 0 | } |
1211 | |
|
1212 | 0 | if (!xStream.is() && getUserAllowsLinkUpdate()) |
1213 | 0 | { |
1214 | | // the image must be regenerated |
1215 | | // TODO/LATER: another aspect could be used |
1216 | 0 | if (xObj->getCurrentState() == embed::EmbedStates::LOADED) |
1217 | 0 | bSwitchBackToLoaded = true; |
1218 | |
|
1219 | 0 | xStream = GetGraphicReplacementStream(embed::Aspects::MSOLE_CONTENT, xObj, |
1220 | 0 | &aMediaType); |
1221 | 0 | } |
1222 | 0 | } |
1223 | |
|
1224 | 0 | if ( _bOasisFormat || (xLink.is() && xLink->isLink()) ) |
1225 | 0 | { |
1226 | 0 | if ( xStream.is() ) |
1227 | 0 | { |
1228 | 0 | if ( _bOasisFormat ) |
1229 | 0 | { |
1230 | | // if it is an embedded object or the optimized inserting fails the normal inserting should be done |
1231 | 0 | if ( _bCreateEmbedded |
1232 | 0 | || !aCnt.InsertGraphicStreamDirectly(xStream, name, aMediaType)) |
1233 | 0 | aCnt.InsertGraphicStream(xStream, name, aMediaType); |
1234 | 0 | } |
1235 | 0 | else |
1236 | 0 | { |
1237 | | // it is a linked object exported into SO7 format |
1238 | 0 | InsertStreamIntoPicturesStorage_Impl(_xStorage, xStream, name); |
1239 | 0 | } |
1240 | 0 | } |
1241 | 0 | } |
1242 | |
|
1243 | 0 | uno::Reference< embed::XEmbedPersist > xPersist( xObj, uno::UNO_QUERY ); |
1244 | 0 | if ( xPersist.is() ) |
1245 | 0 | { |
1246 | 0 | uno::Sequence< beans::PropertyValue > aArgs( _bOasisFormat ? 3 : 4 ); |
1247 | 0 | auto pArgs = aArgs.getArray(); |
1248 | 0 | pArgs[0].Name = "StoreVisualReplacement"; |
1249 | 0 | pArgs[0].Value <<= !_bOasisFormat; |
1250 | | |
1251 | | // if it is an embedded object or the optimized inserting fails the normal inserting should be done |
1252 | 0 | pArgs[1].Name = "CanTryOptimization"; |
1253 | 0 | pArgs[1].Value <<= !_bCreateEmbedded; |
1254 | |
|
1255 | 0 | pArgs[2].Name = "AutoSaveEvent"; |
1256 | 0 | pArgs[2].Value <<= _bAutoSaveEvent; |
1257 | |
|
1258 | 0 | if ( !_bOasisFormat ) |
1259 | 0 | { |
1260 | | // if object has no cached replacement it will use this one |
1261 | 0 | pArgs[3].Name = "VisualReplacement"; |
1262 | 0 | pArgs[3].Value <<= xStream; |
1263 | 0 | } |
1264 | |
|
1265 | 0 | try |
1266 | 0 | { |
1267 | 0 | xPersist->storeAsEntry( _xStorage, xPersist->getEntryName(), uno::Sequence< beans::PropertyValue >(), aArgs ); |
1268 | 0 | } |
1269 | 0 | catch (const embed::WrongStateException&) |
1270 | 0 | { |
1271 | 0 | SAL_WARN("comphelper.container", "failed to store '" << name << "'"); |
1272 | 0 | } |
1273 | 0 | } |
1274 | | |
1275 | 0 | if ( bSwitchBackToLoaded ) |
1276 | | // switch back to loaded state; that way we have a minimum cache confusion |
1277 | 0 | xObj->changeState( embed::EmbedStates::LOADED ); |
1278 | 0 | } |
1279 | 0 | } |
1280 | | |
1281 | 0 | bResult = aCnt.CommitImageSubStorage(); |
1282 | |
|
1283 | 0 | } |
1284 | 0 | catch (const uno::Exception& e) |
1285 | 0 | { |
1286 | | // TODO/LATER: error handling |
1287 | 0 | bResult = false; |
1288 | 0 | SAL_WARN("comphelper.container", "failed. Message: " << e); |
1289 | 0 | } |
1290 | | |
1291 | | // the old SO6 format does not store graphical replacements |
1292 | 0 | if ( !_bOasisFormat && bResult ) |
1293 | 0 | { |
1294 | 0 | try |
1295 | 0 | { |
1296 | | // the substorage still can not be locked by the embedded object container |
1297 | 0 | OUString aObjReplElement( u"ObjectReplacements"_ustr ); |
1298 | 0 | if ( _xStorage->hasByName( aObjReplElement ) && _xStorage->isStorageElement( aObjReplElement ) ) |
1299 | 0 | _xStorage->removeElement( aObjReplElement ); |
1300 | 0 | } |
1301 | 0 | catch (const uno::Exception&) |
1302 | 0 | { |
1303 | | // TODO/LATER: error handling; |
1304 | 0 | bResult = false; |
1305 | 0 | } |
1306 | 0 | } |
1307 | 0 | return bResult; |
1308 | 0 | } |
1309 | | |
1310 | | bool EmbeddedObjectContainer::StoreChildren(bool _bOasisFormat,bool _bObjectsOnly) |
1311 | 0 | { |
1312 | 0 | bool bResult = true; |
1313 | 0 | for (auto& name : GetObjectNames()) |
1314 | 0 | { |
1315 | 0 | try |
1316 | 0 | { |
1317 | 0 | uno::Reference<embed::XEmbeddedObject> xObj = GetEmbeddedObject(name); |
1318 | 0 | SAL_WARN_IF( !xObj.is(), "comphelper.container", "An empty entry in the embedded objects list!" ); |
1319 | 0 | if ( xObj.is() ) |
1320 | 0 | { |
1321 | 0 | sal_Int32 nCurState = xObj->getCurrentState(); |
1322 | 0 | if ( _bOasisFormat && nCurState != embed::EmbedStates::LOADED && nCurState != embed::EmbedStates::RUNNING ) |
1323 | 0 | { |
1324 | | // means that the object is active |
1325 | | // the image must be regenerated |
1326 | 0 | OUString aMediaType; |
1327 | | |
1328 | | // TODO/LATER: another aspect could be used |
1329 | 0 | uno::Reference < io::XInputStream > xStream = |
1330 | 0 | GetGraphicReplacementStream( |
1331 | 0 | embed::Aspects::MSOLE_CONTENT, |
1332 | 0 | xObj, |
1333 | 0 | &aMediaType ); |
1334 | 0 | if ( xStream.is() ) |
1335 | 0 | { |
1336 | 0 | if (!InsertGraphicStreamDirectly(xStream, name, aMediaType)) |
1337 | 0 | InsertGraphicStream(xStream, name, aMediaType); |
1338 | 0 | } |
1339 | 0 | } |
1340 | | |
1341 | | // TODO/LATER: currently the object by default does not cache replacement image |
1342 | | // that means that if somebody loads SO7 document and store its objects using |
1343 | | // this method the images might be lost. |
1344 | | // Currently this method is only used on storing to alien formats, that means |
1345 | | // that SO7 documents storing does not use it, and all other filters are |
1346 | | // based on OASIS format. But if it changes the method must be fixed. The fix |
1347 | | // must be done only on demand since it can affect performance. |
1348 | |
|
1349 | 0 | uno::Reference< embed::XEmbedPersist > xPersist( xObj, uno::UNO_QUERY ); |
1350 | 0 | if ( xPersist.is() ) |
1351 | 0 | { |
1352 | 0 | try |
1353 | 0 | { |
1354 | | //TODO/LATER: only storing if changed! |
1355 | | //xPersist->storeOwn(); //commented, i120168 |
1356 | | |
1357 | | // begin:all charts will be persisted as xml format on disk when saving, which is time consuming. |
1358 | | // '_bObjectsOnly' mean we are storing to alien formats. |
1359 | | // 'isStorageElement' mean current object is NOT a MS OLE format. (may also include in future), i120168 |
1360 | 0 | if (_bObjectsOnly && (nCurState == embed::EmbedStates::LOADED || nCurState == embed::EmbedStates::RUNNING) |
1361 | 0 | && (pImpl->mxStorage->isStorageElement(name))) |
1362 | 0 | { |
1363 | 0 | uno::Reference< util::XModifiable > xModifiable( xObj->getComponent(), uno::UNO_QUERY ); |
1364 | 0 | if ( xModifiable.is() && xModifiable->isModified()) |
1365 | 0 | { |
1366 | 0 | xPersist->storeOwn(); |
1367 | 0 | } |
1368 | 0 | else |
1369 | 0 | { |
1370 | | //do nothing. Embedded model is not modified, no need to persist. |
1371 | 0 | } |
1372 | 0 | } |
1373 | 0 | else //the embedded object is in active status, always store back it. |
1374 | 0 | { |
1375 | 0 | xPersist->storeOwn(); |
1376 | 0 | } |
1377 | | //end i120168 |
1378 | 0 | } |
1379 | 0 | catch (const uno::Exception&) |
1380 | 0 | { |
1381 | | // TODO/LATER: error handling |
1382 | 0 | bResult = false; |
1383 | 0 | break; |
1384 | 0 | } |
1385 | 0 | } |
1386 | | |
1387 | 0 | if ( !_bOasisFormat && !_bObjectsOnly ) |
1388 | 0 | { |
1389 | | // copy replacement images for linked objects |
1390 | 0 | try |
1391 | 0 | { |
1392 | 0 | uno::Reference< embed::XLinkageSupport > xLink( xObj, uno::UNO_QUERY ); |
1393 | 0 | if ( xLink.is() && xLink->isLink() ) |
1394 | 0 | { |
1395 | 0 | OUString aMediaType; |
1396 | 0 | uno::Reference < io::XInputStream > xInStream = GetGraphicStream( xObj, &aMediaType ); |
1397 | 0 | if ( xInStream.is() ) |
1398 | 0 | InsertStreamIntoPicturesStorage_Impl( pImpl->mxStorage, xInStream, name ); |
1399 | 0 | } |
1400 | 0 | } |
1401 | 0 | catch (const uno::Exception&) |
1402 | 0 | { |
1403 | 0 | } |
1404 | 0 | } |
1405 | 0 | } |
1406 | 0 | } |
1407 | 0 | catch (const uno::Exception&) |
1408 | 0 | { |
1409 | | // TODO/LATER: error handling |
1410 | 0 | } |
1411 | 0 | } |
1412 | | |
1413 | 0 | if ( bResult && _bOasisFormat ) |
1414 | 0 | bResult = CommitImageSubStorage(); |
1415 | |
|
1416 | 0 | if ( bResult && !_bObjectsOnly ) |
1417 | 0 | { |
1418 | 0 | try |
1419 | 0 | { |
1420 | 0 | ReleaseImageSubStorage(); |
1421 | 0 | OUString aObjReplElement( u"ObjectReplacements"_ustr ); |
1422 | 0 | if ( !_bOasisFormat && pImpl->mxStorage->hasByName( aObjReplElement ) && pImpl->mxStorage->isStorageElement( aObjReplElement ) ) |
1423 | 0 | pImpl->mxStorage->removeElement( aObjReplElement ); |
1424 | 0 | } |
1425 | 0 | catch (const uno::Exception&) |
1426 | 0 | { |
1427 | | // TODO/LATER: error handling |
1428 | 0 | bResult = false; |
1429 | 0 | } |
1430 | 0 | } |
1431 | 0 | return bResult; |
1432 | 0 | } |
1433 | | |
1434 | | uno::Reference< io::XInputStream > EmbeddedObjectContainer::GetGraphicReplacementStream( |
1435 | | sal_Int64 nViewAspect, |
1436 | | const uno::Reference< embed::XEmbeddedObject >& xObj, |
1437 | | OUString* pMediaType ) |
1438 | 0 | { |
1439 | 0 | if ( !xObj.is() ) |
1440 | 0 | return nullptr; |
1441 | | |
1442 | 0 | rtl::Reference< ::comphelper::SequenceInputStream > xInStream; |
1443 | 0 | try |
1444 | 0 | { |
1445 | | // retrieving of the visual representation can switch object to running state |
1446 | 0 | embed::VisualRepresentation aRep = xObj->getPreferredVisualRepresentation( nViewAspect ); |
1447 | 0 | if ( pMediaType ) |
1448 | 0 | *pMediaType = aRep.Flavor.MimeType; |
1449 | |
|
1450 | 0 | uno::Sequence < sal_Int8 > aSeq; |
1451 | 0 | aRep.Data >>= aSeq; |
1452 | 0 | xInStream = new ::comphelper::SequenceInputStream( aSeq ); |
1453 | 0 | } |
1454 | 0 | catch (const uno::Exception&) |
1455 | 0 | { |
1456 | 0 | } |
1457 | |
|
1458 | 0 | return xInStream; |
1459 | 0 | } |
1460 | | |
1461 | | bool EmbeddedObjectContainer::SetPersistentEntries(const uno::Reference< embed::XStorage >& _xStorage,bool _bClearModifiedFlag) |
1462 | 0 | { |
1463 | 0 | bool bError = false; |
1464 | 0 | for (auto& name : GetObjectNames()) |
1465 | 0 | { |
1466 | 0 | uno::Reference<embed::XEmbeddedObject> xObj = GetEmbeddedObject(name); |
1467 | 0 | SAL_WARN_IF( !xObj.is(), "comphelper.container", "An empty entry in the embedded objects list!" ); |
1468 | 0 | if ( xObj.is() ) |
1469 | 0 | { |
1470 | 0 | uno::Reference< embed::XEmbedPersist > xPersist( xObj, uno::UNO_QUERY ); |
1471 | 0 | if ( xPersist.is() ) |
1472 | 0 | { |
1473 | 0 | try |
1474 | 0 | { |
1475 | 0 | xPersist->setPersistentEntry( _xStorage, |
1476 | 0 | name, |
1477 | 0 | embed::EntryInitModes::NO_INIT, |
1478 | 0 | uno::Sequence< beans::PropertyValue >(), |
1479 | 0 | uno::Sequence< beans::PropertyValue >() ); |
1480 | |
|
1481 | 0 | } |
1482 | 0 | catch (const uno::Exception&) |
1483 | 0 | { |
1484 | | // TODO/LATER: error handling |
1485 | 0 | bError = true; |
1486 | 0 | break; |
1487 | 0 | } |
1488 | 0 | } |
1489 | 0 | if ( _bClearModifiedFlag ) |
1490 | 0 | { |
1491 | | // if this method is used as part of SaveCompleted the object must stay unmodified after execution |
1492 | 0 | try |
1493 | 0 | { |
1494 | 0 | uno::Reference< util::XModifiable > xModif( xObj->getComponent(), uno::UNO_QUERY ); |
1495 | 0 | if ( xModif && xModif->isModified() ) |
1496 | 0 | xModif->setModified( false ); |
1497 | 0 | } |
1498 | 0 | catch (const uno::Exception&) |
1499 | 0 | { |
1500 | 0 | } |
1501 | 0 | } |
1502 | 0 | } |
1503 | 0 | } |
1504 | 0 | return bError; |
1505 | 0 | } |
1506 | | |
1507 | | bool EmbeddedObjectContainer::getUserAllowsLinkUpdate() const |
1508 | 216k | { |
1509 | 216k | if (officecfg::Office::Common::Security::Scripting::DisableActiveContent::get()) |
1510 | 0 | return false; |
1511 | 216k | return pImpl->mbUserAllowsLinkUpdate; |
1512 | 216k | } |
1513 | | |
1514 | | void EmbeddedObjectContainer::setUserAllowsLinkUpdate(bool bNew) |
1515 | 26.4k | { |
1516 | 26.4k | if(pImpl->mbUserAllowsLinkUpdate != bNew) |
1517 | 26.4k | { |
1518 | 26.4k | pImpl->mbUserAllowsLinkUpdate = bNew; |
1519 | 26.4k | } |
1520 | 26.4k | } |
1521 | | |
1522 | | } |
1523 | | |
1524 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |