bump product version to 5.0.4.1
[LibreOffice.git] / svx / source / svdraw / svdomedia.cxx
blob074d2faaaae520f61d0f86daf0b1a3651db2ee2b
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <config_features.h>
22 #include <svx/svdomedia.hxx>
24 #include <rtl/ustring.hxx>
25 #include <osl/file.hxx>
27 #include <com/sun/star/document/XStorageBasedDocument.hpp>
28 #include <com/sun/star/embed/XStorage.hpp>
30 #include <ucbhelper/content.hxx>
31 #include <comphelper/processfactory.hxx>
32 #include <comphelper/storagehelper.hxx>
34 #include <vcl/svapp.hxx>
36 #include <svx/svdmodel.hxx>
37 #include "svdglob.hxx"
38 #include "svx/svdstr.hrc"
39 #include <svx/sdr/contact/viewcontactofsdrmediaobj.hxx>
40 #include <avmedia/mediawindow.hxx>
42 // For handling of glTF models
43 #include <unotools/tempfile.hxx>
44 #include <unotools/localfilehelper.hxx>
45 #include <tools/urlobj.hxx>
47 using namespace ::com::sun::star;
50 // - SdrMediaObj -
52 // Note: the temp file is read only, until it is deleted!
53 // It may be shared between multiple documents in case of copy/paste,
54 // hence the shared_ptr.
55 struct MediaTempFile
57 OUString const m_TempFileURL;
58 OUString const m_TempDirURL; // yet another hack, for the glTF models
59 MediaTempFile(OUString const& rURL, OUString const& rDirURL)
60 : m_TempFileURL(rURL), m_TempDirURL(rDirURL)
62 ~MediaTempFile()
64 ::osl::File::remove(m_TempFileURL);
65 if (!m_TempDirURL.isEmpty())
67 ::utl::removeTree(m_TempDirURL);
72 struct SdrMediaObj::Impl
74 ::avmedia::MediaItem m_MediaProperties;
75 ::boost::shared_ptr< MediaTempFile > m_pTempFile;
76 uno::Reference< graphic::XGraphic > m_xCachedSnapshot;
77 OUString m_LastFailedPkgURL;
80 TYPEINIT1( SdrMediaObj, SdrRectObj );
84 SdrMediaObj::SdrMediaObj()
85 : SdrRectObj()
86 , m_xImpl( new Impl() )
90 SdrMediaObj::SdrMediaObj( const Rectangle& rRect )
91 : SdrRectObj( rRect )
92 , m_xImpl( new Impl() )
96 SdrMediaObj::~SdrMediaObj()
100 bool SdrMediaObj::HasTextEdit() const
102 return false;
105 sdr::contact::ViewContact* SdrMediaObj::CreateObjectSpecificViewContact()
107 return new sdr::contact::ViewContactOfSdrMediaObj( *this );
110 void SdrMediaObj::TakeObjInfo( SdrObjTransformInfoRec& rInfo ) const
112 rInfo.bSelectAllowed = true;
113 rInfo.bMoveAllowed = true;
114 rInfo.bResizeFreeAllowed = true;
115 rInfo.bResizePropAllowed = true;
116 rInfo.bRotateFreeAllowed = false;
117 rInfo.bRotate90Allowed = false;
118 rInfo.bMirrorFreeAllowed = false;
119 rInfo.bMirror45Allowed = false;
120 rInfo.bMirror90Allowed = false;
121 rInfo.bTransparenceAllowed = false;
122 rInfo.bGradientAllowed = false;
123 rInfo.bShearAllowed = false;
124 rInfo.bEdgeRadiusAllowed = false;
125 rInfo.bNoOrthoDesired = false;
126 rInfo.bNoContortion = false;
127 rInfo.bCanConvToPath = false;
128 rInfo.bCanConvToPoly = false;
129 rInfo.bCanConvToContour = false;
130 rInfo.bCanConvToPathLineToArea = false;
131 rInfo.bCanConvToPolyLineToArea = false;
134 sal_uInt16 SdrMediaObj::GetObjIdentifier() const
136 return sal_uInt16( OBJ_MEDIA );
139 OUString SdrMediaObj::TakeObjNameSingul() const
141 OUStringBuffer sName(ImpGetResStr(STR_ObjNameSingulMEDIA));
143 OUString aName(GetName());
145 if (!aName.isEmpty())
147 sName.append(' ');
148 sName.append('\'');
149 sName.append(aName);
150 sName.append('\'');
153 return sName.makeStringAndClear();
156 OUString SdrMediaObj::TakeObjNamePlural() const
158 return ImpGetResStr(STR_ObjNamePluralMEDIA);
161 SdrMediaObj* SdrMediaObj::Clone() const
163 return CloneHelper< SdrMediaObj >();
166 SdrMediaObj& SdrMediaObj::operator=(const SdrMediaObj& rObj)
168 if( this == &rObj )
169 return *this;
170 SdrRectObj::operator=( rObj );
172 m_xImpl->m_pTempFile = rObj.m_xImpl->m_pTempFile; // before props
173 setMediaProperties( rObj.getMediaProperties() );
174 m_xImpl->m_xCachedSnapshot = rObj.m_xImpl->m_xCachedSnapshot;
175 return *this;
178 const uno::Reference< graphic::XGraphic > SdrMediaObj::getSnapshot() const
180 if( !m_xImpl->m_xCachedSnapshot.is() )
182 OUString aRealURL = m_xImpl->m_MediaProperties.getTempURL();
183 if( aRealURL.isEmpty() )
184 aRealURL = m_xImpl->m_MediaProperties.getURL();
185 m_xImpl->m_xCachedSnapshot = avmedia::MediaWindow::grabFrame( aRealURL, m_xImpl->m_MediaProperties.getReferer(), m_xImpl->m_MediaProperties.getMimeType());
187 return m_xImpl->m_xCachedSnapshot;
190 void SdrMediaObj::AdjustToMaxRect( const Rectangle& rMaxRect, bool bShrinkOnly /* = false */ )
192 Size aSize( Application::GetDefaultDevice()->PixelToLogic( getPreferredSize(), MAP_100TH_MM ) );
193 Size aMaxSize( rMaxRect.GetSize() );
195 if( aSize.Height() != 0 && aSize.Width() != 0 )
197 Point aPos( rMaxRect.TopLeft() );
199 // if graphic is too large, fit it to the page
200 if ( (!bShrinkOnly ||
201 ( aSize.Height() > aMaxSize.Height() ) ||
202 ( aSize.Width() > aMaxSize.Width() ) )&&
203 aSize.Height() && aMaxSize.Height() )
205 float fGrfWH = (float)aSize.Width() /
206 (float)aSize.Height();
207 float fWinWH = (float)aMaxSize.Width() /
208 (float)aMaxSize.Height();
210 // scale graphic to page size
211 if ( fGrfWH < fWinWH )
213 aSize.Width() = (long)(aMaxSize.Height() * fGrfWH);
214 aSize.Height()= aMaxSize.Height();
216 else if ( fGrfWH > 0.F )
218 aSize.Width() = aMaxSize.Width();
219 aSize.Height()= (long)(aMaxSize.Width() / fGrfWH);
222 aPos = rMaxRect.Center();
225 if( bShrinkOnly )
226 aPos = maRect.TopLeft();
228 aPos.X() -= aSize.Width() / 2;
229 aPos.Y() -= aSize.Height() / 2;
230 SetLogicRect( Rectangle( aPos, aSize ) );
234 void SdrMediaObj::setURL( const OUString& rURL, const OUString& rReferer, const OUString& rMimeType )
236 ::avmedia::MediaItem aURLItem;
237 if( !rMimeType.isEmpty() )
238 m_xImpl->m_MediaProperties.setMimeType(rMimeType);
239 aURLItem.setURL( rURL, "", rReferer );
240 setMediaProperties( aURLItem );
243 const OUString& SdrMediaObj::getURL() const
245 return m_xImpl->m_MediaProperties.getURL();
248 void SdrMediaObj::setMediaProperties( const ::avmedia::MediaItem& rState )
250 mediaPropertiesChanged( rState );
251 static_cast< sdr::contact::ViewContactOfSdrMediaObj& >( GetViewContact() ).executeMediaItem( getMediaProperties() );
254 const ::avmedia::MediaItem& SdrMediaObj::getMediaProperties() const
256 return m_xImpl->m_MediaProperties;
259 Size SdrMediaObj::getPreferredSize() const
261 return static_cast< sdr::contact::ViewContactOfSdrMediaObj& >( GetViewContact() ).getPreferredSize();
264 uno::Reference<io::XInputStream> SdrMediaObj::GetInputStream()
266 if (!m_xImpl->m_pTempFile)
268 SAL_WARN("svx", "this is only intended for embedded media");
269 return 0;
271 ucbhelper::Content tempFile(m_xImpl->m_pTempFile->m_TempFileURL,
272 uno::Reference<ucb::XCommandEnvironment>(),
273 comphelper::getProcessComponentContext());
274 return tempFile.openStream();
277 #if HAVE_FEATURE_GLTF
278 static bool lcl_HandleJsonPackageURL(
279 const OUString& rURL,
280 SdrModel* const pModel,
281 OUString& o_rTempFileURL,
282 OUString& o_rTempDirURL)
284 // Create a temporary folder which will contain all files of glTF model
285 o_rTempDirURL = ::utl::TempFile(NULL, true).GetURL();
287 const sal_uInt16 nPackageLength = OString("vnd.sun.star.Package:").getLength();
288 const OUString sUrlPath = rURL.copy(nPackageLength,rURL.lastIndexOf("/")-nPackageLength);
291 // Base storage:
292 uno::Reference<document::XStorageBasedDocument> const xSBD(
293 pModel->getUnoModel(), uno::UNO_QUERY_THROW);
294 const uno::Reference<embed::XStorage> xStorage(
295 xSBD->getDocumentStorage(), uno::UNO_QUERY_THROW);
297 // Model source
298 ::comphelper::LifecycleProxy proxy;
299 const uno::Reference<embed::XStorage> xModelStorage(
300 ::comphelper::OStorageHelper::GetStorageAtPath(xStorage, sUrlPath,
301 embed::ElementModes::READ, proxy));
303 // Copy all files of glTF model from storage to the temp folder
304 uno::Reference< container::XNameAccess > xNameAccess( xModelStorage, uno::UNO_QUERY );
305 const uno::Sequence< OUString > aFilenames = xNameAccess->getElementNames();
306 for( sal_Int32 nFileIndex = 0; nFileIndex < aFilenames.getLength(); ++nFileIndex )
308 // Generate temp file path
309 const OUString& rFilename = aFilenames[nFileIndex];
310 INetURLObject aUrlObj(o_rTempDirURL);
311 aUrlObj.insertName(rFilename);
312 const OUString sFilepath = aUrlObj.GetMainURL( INetURLObject::NO_DECODE );
314 // Media URL will point at json file
315 if( rFilename.endsWith(".json") )
316 o_rTempFileURL = sFilepath;
318 // Create temp file and fill it from storage
319 ::ucbhelper::Content aTargetContent(sFilepath,
320 uno::Reference<ucb::XCommandEnvironment>(), comphelper::getProcessComponentContext());
322 uno::Reference<io::XStream> const xStream(
323 xModelStorage->openStreamElement(rFilename,embed::ElementModes::READ), uno::UNO_SET_THROW);
324 uno::Reference<io::XInputStream> const xInputStream(
325 xStream->getInputStream(), uno::UNO_SET_THROW);
327 aTargetContent.writeStream(xInputStream,true);
331 catch (uno::Exception const& e)
333 SAL_INFO("svx", "exception while copying glTF related files to temp directory '" << e.Message << "'");
335 return true;
337 #endif
339 static bool lcl_CopyToTempFile(
340 uno::Reference<io::XInputStream> const& xInStream,
341 OUString & o_rTempFileURL)
343 OUString tempFileURL;
344 ::osl::FileBase::RC const err =
345 ::osl::FileBase::createTempFile(0, 0, & tempFileURL);
346 if (::osl::FileBase::E_None != err)
348 SAL_INFO("svx", "cannot create temp file");
349 return false;
354 ::ucbhelper::Content tempContent(tempFileURL,
355 uno::Reference<ucb::XCommandEnvironment>(),
356 comphelper::getProcessComponentContext());
357 tempContent.writeStream(xInStream, true); // copy stream to file
359 catch (uno::Exception const& e)
361 SAL_WARN("svx", "exception: '" << e.Message << "'");
362 return false;
364 o_rTempFileURL = tempFileURL;
365 return true;
368 void SdrMediaObj::SetInputStream(uno::Reference<io::XInputStream> const& xStream)
370 if (m_xImpl->m_pTempFile || m_xImpl->m_LastFailedPkgURL.isEmpty())
372 SAL_WARN("svx", "this is only intended for embedded media");
373 return;
375 OUString tempFileURL;
376 bool const bSuccess = lcl_CopyToTempFile(xStream, tempFileURL);
377 if (bSuccess)
379 m_xImpl->m_pTempFile.reset(new MediaTempFile(tempFileURL, ""));
380 m_xImpl->m_MediaProperties.setURL(
381 m_xImpl->m_LastFailedPkgURL, tempFileURL, "");
383 m_xImpl->m_LastFailedPkgURL.clear(); // once only
386 /// copy a stream from XStorage to temp file
387 static bool lcl_HandlePackageURL(
388 OUString const & rURL,
389 SdrModel *const pModel,
390 OUString & o_rTempFileURL)
392 if (!pModel)
394 SAL_WARN("svx", "no model");
395 return false;
397 ::comphelper::LifecycleProxy sourceProxy;
398 uno::Reference<io::XInputStream> xInStream;
399 try {
400 xInStream = pModel->GetDocumentStream(rURL, sourceProxy);
402 catch (container::NoSuchElementException const&)
404 SAL_INFO("svx", "not found: '" << OUString(rURL) << "'");
405 return false;
407 catch (uno::Exception const& e)
409 SAL_WARN("svx", "exception: '" << e.Message << "'");
410 return false;
412 if (!xInStream.is())
414 SAL_WARN("svx", "no stream?");
415 return false;
417 return lcl_CopyToTempFile(xInStream, o_rTempFileURL);
420 void SdrMediaObj::mediaPropertiesChanged( const ::avmedia::MediaItem& rNewProperties )
422 bool bBroadcastChanged = false;
423 const AVMediaSetMask nMaskSet = rNewProperties.getMaskSet();
425 // use only a subset of MediaItem properties for own own properties
426 if( AVMediaSetMask::MIME_TYPE & nMaskSet )
427 m_xImpl->m_MediaProperties.setMimeType( rNewProperties.getMimeType() );
429 if( ( AVMediaSetMask::URL & nMaskSet ) &&
430 ( rNewProperties.getURL() != getURL() ))
432 m_xImpl->m_xCachedSnapshot.clear();
433 OUString const url(rNewProperties.getURL());
434 if (url.startsWithIgnoreAsciiCase("vnd.sun.star.Package:"))
436 if ( !m_xImpl->m_pTempFile
437 || (m_xImpl->m_pTempFile->m_TempFileURL !=
438 rNewProperties.getTempURL()))
440 OUString tempFileURL;
441 OUString tempDirURL;
442 bool bSuccess;
443 #if HAVE_FEATURE_GLTF
444 if( url.endsWith(".json") )
445 bSuccess = lcl_HandleJsonPackageURL(url, GetModel(), tempFileURL, tempDirURL);
446 else
447 #endif
448 bSuccess = lcl_HandlePackageURL(url, GetModel(), tempFileURL);
449 if (bSuccess)
451 m_xImpl->m_pTempFile.reset(
452 new MediaTempFile(tempFileURL, tempDirURL));
453 m_xImpl->m_MediaProperties.setURL(url, tempFileURL, "");
455 else // this case is for Clone via operator=
457 m_xImpl->m_pTempFile.reset();
458 m_xImpl->m_MediaProperties.setURL("", "", "");
459 // UGLY: oox import also gets here, because unlike ODF
460 // getDocumentStorage() is not the imported file...
461 m_xImpl->m_LastFailedPkgURL = url;
464 else
466 m_xImpl->m_MediaProperties.setURL(url,
467 rNewProperties.getTempURL(), "");
470 else
472 m_xImpl->m_pTempFile.reset();
473 m_xImpl->m_MediaProperties.setURL(url, "", rNewProperties.getReferer());
475 bBroadcastChanged = true;
478 if( AVMediaSetMask::LOOP & nMaskSet )
479 m_xImpl->m_MediaProperties.setLoop( rNewProperties.isLoop() );
481 if( AVMediaSetMask::MUTE & nMaskSet )
482 m_xImpl->m_MediaProperties.setMute( rNewProperties.isMute() );
484 if( AVMediaSetMask::VOLUMEDB & nMaskSet )
485 m_xImpl->m_MediaProperties.setVolumeDB( rNewProperties.getVolumeDB() );
487 if( AVMediaSetMask::ZOOM & nMaskSet )
488 m_xImpl->m_MediaProperties.setZoom( rNewProperties.getZoom() );
490 if( bBroadcastChanged )
492 SetChanged();
493 BroadcastObjectChange();
497 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */