tdf#130857 qt weld: Implement QtInstanceWidget::get_text_height
[LibreOffice.git] / avmedia / source / framework / mediaitem.cxx
blobc2ecaa29d9bf501e9e20ade5d5d10d9b8a898a0d
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 <avmedia/mediaitem.hxx>
22 #include <com/sun/star/uno/Sequence.hxx>
24 #include <com/sun/star/beans/XPropertySet.hpp>
25 #include <com/sun/star/embed/ElementModes.hpp>
26 #include <com/sun/star/embed/XTransactedObject.hpp>
27 #include <com/sun/star/frame/XModel.hpp>
28 #include <com/sun/star/document/XStorageBasedDocument.hpp>
29 #include <com/sun/star/ucb/XCommandEnvironment.hpp>
30 #include <com/sun/star/uri/UriReferenceFactory.hpp>
31 #include <com/sun/star/uri/XUriReference.hpp>
32 #include <com/sun/star/uri/XUriReferenceFactory.hpp>
33 #include <com/sun/star/text/GraphicCrop.hpp>
35 #include <sal/log.hxx>
37 #include <ucbhelper/content.hxx>
39 #include <comphelper/mediamimetype.hxx>
40 #include <comphelper/processfactory.hxx>
41 #include <comphelper/storagehelper.hxx>
42 #include <mediamisc.hxx>
43 #include <osl/file.hxx>
44 #include <comphelper/diagnose_ex.hxx>
45 #include <vcl/graph.hxx>
47 using namespace ::com::sun::star;
49 namespace avmedia
52 SfxPoolItem* MediaItem::CreateDefault() { return new MediaItem; }
54 struct MediaItem::Impl
56 OUString m_URL;
57 OUString m_TempFileURL;
58 OUString m_FallbackURL;
59 OUString m_Referer;
60 OUString m_sMimeType;
61 AVMediaSetMask m_nMaskSet;
62 MediaState m_eState;
63 double m_fTime;
64 double m_fDuration;
65 sal_Int16 m_nVolumeDB;
66 bool m_bLoop;
67 bool m_bMute;
68 css::media::ZoomLevel m_eZoom;
69 Graphic m_aGraphic;
70 text::GraphicCrop m_aCrop;
72 explicit Impl(AVMediaSetMask nMaskSet)
73 : m_nMaskSet( nMaskSet )
74 , m_eState( MediaState::Stop )
75 , m_fTime( 0.0 )
76 , m_fDuration( 0.0 )
77 , m_nVolumeDB( 0 )
78 , m_bLoop( false )
79 , m_bMute( false )
80 , m_eZoom( css::media::ZoomLevel_NOT_AVAILABLE )
86 MediaItem::MediaItem( sal_uInt16 i_nWhich, AVMediaSetMask nMaskSet )
87 : SfxPoolItem( i_nWhich, SfxItemType::MediaItemType )
88 , m_pImpl( new Impl(nMaskSet) )
93 MediaItem::MediaItem( const MediaItem& rItem )
94 : SfxPoolItem( rItem )
95 , m_pImpl( new Impl(*rItem.m_pImpl) )
100 MediaItem::~MediaItem()
105 bool MediaItem::operator==( const SfxPoolItem& rItem ) const
107 assert( SfxPoolItem::operator==(rItem));
108 MediaItem const& rOther(static_cast< const MediaItem& >(rItem));
109 return m_pImpl->m_nMaskSet == rOther.m_pImpl->m_nMaskSet
110 && m_pImpl->m_URL == rOther.m_pImpl->m_URL
111 && m_pImpl->m_FallbackURL == rOther.m_pImpl->m_FallbackURL
112 && m_pImpl->m_Referer == rOther.m_pImpl->m_Referer
113 && m_pImpl->m_sMimeType == rOther.m_pImpl->m_sMimeType
114 && m_pImpl->m_aGraphic == rOther.m_pImpl->m_aGraphic
115 && m_pImpl->m_aCrop == rOther.m_pImpl->m_aCrop
116 && m_pImpl->m_eState == rOther.m_pImpl->m_eState
117 && m_pImpl->m_fDuration == rOther.m_pImpl->m_fDuration
118 && m_pImpl->m_fTime == rOther.m_pImpl->m_fTime
119 && m_pImpl->m_nVolumeDB == rOther.m_pImpl->m_nVolumeDB
120 && m_pImpl->m_bLoop == rOther.m_pImpl->m_bLoop
121 && m_pImpl->m_bMute == rOther.m_pImpl->m_bMute
122 && m_pImpl->m_eZoom == rOther.m_pImpl->m_eZoom;
125 MediaItem* MediaItem::Clone( SfxItemPool* ) const
127 return new MediaItem( *this );
130 bool MediaItem::GetPresentation( SfxItemPresentation,
131 MapUnit,
132 MapUnit,
133 OUString& rText,
134 const IntlWrapper& ) const
136 rText.clear();
137 return false;
140 bool MediaItem::QueryValue( css::uno::Any& rVal, sal_uInt8 ) const
142 uno::Sequence< uno::Any > aSeq{ uno::Any(m_pImpl->m_URL),
143 uno::Any(static_cast<sal_uInt32>(m_pImpl->m_nMaskSet)),
144 uno::Any(static_cast< sal_Int32 >( m_pImpl->m_eState )),
145 uno::Any(m_pImpl->m_fTime),
146 uno::Any(m_pImpl->m_fDuration),
147 uno::Any(m_pImpl->m_nVolumeDB),
148 uno::Any(m_pImpl->m_bLoop),
149 uno::Any(m_pImpl->m_bMute),
150 uno::Any(m_pImpl->m_eZoom),
151 uno::Any(m_pImpl->m_sMimeType) };
153 rVal <<= aSeq;
155 return true;
159 bool MediaItem::PutValue( const css::uno::Any& rVal, sal_uInt8 )
161 uno::Sequence< uno::Any > aSeq;
162 bool bRet = false;
164 if( ( rVal >>= aSeq ) && ( aSeq.getLength() == 10 ) )
166 sal_Int32 nInt32 = 0;
168 aSeq[ 0 ] >>= m_pImpl->m_URL;
169 aSeq[ 1 ] >>= nInt32;
170 m_pImpl->m_nMaskSet = static_cast<AVMediaSetMask>(nInt32);
171 aSeq[ 2 ] >>= nInt32;
172 m_pImpl->m_eState = static_cast< MediaState >( nInt32 );
173 aSeq[ 3 ] >>= m_pImpl->m_fTime;
174 aSeq[ 4 ] >>= m_pImpl->m_fDuration;
175 aSeq[ 5 ] >>= m_pImpl->m_nVolumeDB;
176 aSeq[ 6 ] >>= m_pImpl->m_bLoop;
177 aSeq[ 7 ] >>= m_pImpl->m_bMute;
178 aSeq[ 8 ] >>= m_pImpl->m_eZoom;
179 aSeq[ 9 ] >>= m_pImpl->m_sMimeType;
181 bRet = true;
184 return bRet;
187 bool MediaItem::merge(const MediaItem& rMediaItem)
189 bool bChanged = false;
191 const AVMediaSetMask nMaskSet = rMediaItem.getMaskSet();
193 if( AVMediaSetMask::URL & nMaskSet )
195 bChanged = m_pImpl->m_FallbackURL == rMediaItem.getFallbackURL();
196 m_pImpl->m_FallbackURL = rMediaItem.getFallbackURL();
197 bChanged |= setURL(rMediaItem.getURL(), rMediaItem.getTempURL(), rMediaItem.getReferer());
200 if( AVMediaSetMask::MIME_TYPE & nMaskSet )
201 bChanged |= setMimeType(rMediaItem.getMimeType());
203 if (nMaskSet & AVMediaSetMask::GRAPHIC)
204 bChanged |= setGraphic(rMediaItem.getGraphic());
206 if (nMaskSet & AVMediaSetMask::CROP)
207 bChanged |= setCrop(rMediaItem.getCrop());
209 if( AVMediaSetMask::STATE & nMaskSet )
210 bChanged |= setState( rMediaItem.getState() );
212 if( AVMediaSetMask::DURATION & nMaskSet )
213 bChanged |= setDuration(rMediaItem.getDuration());
215 if( AVMediaSetMask::TIME & nMaskSet )
216 bChanged |= setTime(rMediaItem.getTime());
218 if( AVMediaSetMask::LOOP & nMaskSet )
219 bChanged |= setLoop(rMediaItem.isLoop());
221 if( AVMediaSetMask::MUTE & nMaskSet )
222 bChanged |= setMute(rMediaItem.isMute());
224 if( AVMediaSetMask::VOLUMEDB & nMaskSet )
225 bChanged |= setVolumeDB(rMediaItem.getVolumeDB());
227 if( AVMediaSetMask::ZOOM & nMaskSet )
228 bChanged |= setZoom(rMediaItem.getZoom());
230 return bChanged;
233 AVMediaSetMask MediaItem::getMaskSet() const
235 return m_pImpl->m_nMaskSet;
238 bool MediaItem::setURL(const OUString& rURL, const OUString& rTempURL, const OUString& rReferer)
240 m_pImpl->m_nMaskSet |= AVMediaSetMask::URL;
241 bool bChanged = rURL != m_pImpl->m_URL || rTempURL != m_pImpl->m_TempFileURL || rReferer != m_pImpl->m_Referer;
242 if (bChanged)
244 m_pImpl->m_URL = rURL;
245 m_pImpl->m_TempFileURL = rTempURL;
246 m_pImpl->m_Referer = rReferer;
247 setMimeType(::comphelper::GuessMediaMimeType(GetFilename(rURL)));
249 return bChanged;
252 const OUString& MediaItem::getURL() const
254 return m_pImpl->m_URL;
257 bool MediaItem::setFallbackURL(const OUString& rURL)
259 bool bChanged = rURL != m_pImpl->m_FallbackURL;
260 if (bChanged)
261 m_pImpl->m_FallbackURL = rURL;
262 return bChanged;
264 const OUString& MediaItem::getFallbackURL() const
266 return m_pImpl->m_FallbackURL;
269 const OUString& MediaItem::getTempURL() const
271 return m_pImpl->m_TempFileURL;
274 const OUString& MediaItem::getReferer() const
276 return m_pImpl->m_Referer;
279 bool MediaItem::setMimeType(const OUString& rMimeType)
281 m_pImpl->m_nMaskSet |= AVMediaSetMask::MIME_TYPE;
282 bool bChanged = rMimeType != m_pImpl->m_sMimeType;
283 if (bChanged)
284 m_pImpl->m_sMimeType = rMimeType;
285 return bChanged;
288 const OUString & MediaItem::getMimeType() const
290 return !m_pImpl->m_sMimeType.isEmpty() ? m_pImpl->m_sMimeType : AVMEDIA_MIMETYPE_COMMON;
293 bool MediaItem::setGraphic(const Graphic& rGraphic)
295 m_pImpl->m_nMaskSet |= AVMediaSetMask::GRAPHIC;
296 bool bChanged = rGraphic != m_pImpl->m_aGraphic;
297 if (bChanged)
298 m_pImpl->m_aGraphic = rGraphic;
299 return bChanged;
302 const Graphic & MediaItem::getGraphic() const { return m_pImpl->m_aGraphic; }
304 bool MediaItem::setCrop(const text::GraphicCrop& rCrop)
306 m_pImpl->m_nMaskSet |= AVMediaSetMask::CROP;
307 bool bChanged = rCrop != m_pImpl->m_aCrop;
308 if (bChanged)
309 m_pImpl->m_aCrop = rCrop;
310 return bChanged;
313 const text::GraphicCrop& MediaItem::getCrop() const { return m_pImpl->m_aCrop; }
315 bool MediaItem::setState(MediaState eState)
317 m_pImpl->m_nMaskSet |= AVMediaSetMask::STATE;
318 bool bChanged = eState != m_pImpl->m_eState;
319 if (bChanged)
320 m_pImpl->m_eState = eState;
321 return bChanged;
324 MediaState MediaItem::getState() const
326 return m_pImpl->m_eState;
329 bool MediaItem::setDuration(double fDuration)
331 m_pImpl->m_nMaskSet |= AVMediaSetMask::DURATION;
332 bool bChanged = fDuration != m_pImpl->m_fDuration;
333 if (bChanged)
334 m_pImpl->m_fDuration = fDuration;
335 return bChanged;
338 double MediaItem::getDuration() const
340 return m_pImpl->m_fDuration;
343 bool MediaItem::setTime(double fTime)
345 m_pImpl->m_nMaskSet |= AVMediaSetMask::TIME;
346 bool bChanged = fTime != m_pImpl->m_fTime;
347 if (bChanged)
348 m_pImpl->m_fTime = fTime;
349 return bChanged;
352 double MediaItem::getTime() const
354 return m_pImpl->m_fTime;
357 bool MediaItem::setLoop(bool bLoop)
359 m_pImpl->m_nMaskSet |= AVMediaSetMask::LOOP;
360 bool bChanged = bLoop != m_pImpl->m_bLoop;
361 if (bChanged)
362 m_pImpl->m_bLoop = bLoop;
363 return bChanged;
366 bool MediaItem::isLoop() const
368 return m_pImpl->m_bLoop;
371 bool MediaItem::setMute(bool bMute)
373 m_pImpl->m_nMaskSet |= AVMediaSetMask::MUTE;
374 bool bChanged = bMute != m_pImpl->m_bMute;
375 if (bChanged)
376 m_pImpl->m_bMute = bMute;
377 return bChanged;
380 bool MediaItem::isMute() const
382 return m_pImpl->m_bMute;
385 bool MediaItem::setVolumeDB(sal_Int16 nDB)
387 m_pImpl->m_nMaskSet |= AVMediaSetMask::VOLUMEDB;
388 bool bChanged = nDB != m_pImpl->m_nVolumeDB;
389 if (bChanged)
390 m_pImpl->m_nVolumeDB = nDB;
391 return bChanged;
394 sal_Int16 MediaItem::getVolumeDB() const
396 return m_pImpl->m_nVolumeDB;
399 bool MediaItem::setZoom(css::media::ZoomLevel eZoom)
401 m_pImpl->m_nMaskSet |= AVMediaSetMask::ZOOM;
402 bool bChanged = eZoom != m_pImpl->m_eZoom;
403 if (bChanged)
404 m_pImpl->m_eZoom = eZoom;
405 return bChanged;
408 css::media::ZoomLevel MediaItem::getZoom() const
410 return m_pImpl->m_eZoom;
413 OUString GetFilename(OUString const& rSourceURL)
415 uno::Reference<uri::XUriReferenceFactory> const xUriFactory(
416 uri::UriReferenceFactory::create(
417 comphelper::getProcessComponentContext()));
418 uno::Reference<uri::XUriReference> const xSourceURI(
419 xUriFactory->parse(rSourceURL), uno::UNO_SET_THROW);
421 OUString filename;
423 sal_Int32 const nSegments(xSourceURI->getPathSegmentCount());
424 if (0 < nSegments)
426 filename = xSourceURI->getPathSegment(nSegments - 1);
429 if (!::comphelper::OStorageHelper::IsValidZipEntryFileName(
430 filename, false) || !filename.getLength())
432 filename = "media";
434 return filename;
438 uno::Reference<io::XStream>
439 CreateStream(uno::Reference<embed::XStorage> const& xStorage,
440 OUString const& rFilename)
442 OUString filename(rFilename);
444 if (xStorage->hasByName(filename))
446 std::u16string_view basename;
447 std::u16string_view suffix;
448 sal_Int32 const nIndex(rFilename.lastIndexOf('.'));
449 if (0 < nIndex)
451 basename = rFilename.subView(0, nIndex);
452 suffix = rFilename.subView(nIndex);
454 sal_Int32 count(0); // sigh... try to generate non-existent name
457 ++count;
458 filename = basename + OUString::number(count) + suffix;
460 while (xStorage->hasByName(filename));
463 uno::Reference<io::XStream> const xStream(
464 xStorage->openStreamElement(filename,
465 embed::ElementModes::WRITE | embed::ElementModes::TRUNCATE),
466 uno::UNO_SET_THROW);
467 uno::Reference< beans::XPropertySet > const xStreamProps(xStream,
468 uno::UNO_QUERY);
469 if (xStreamProps.is()) { // this is NOT supported in FileSystemStorage
470 OUString const guessed(::comphelper::GuessMediaMimeType(filename));
471 xStreamProps->setPropertyValue(u"MediaType"_ustr,
472 uno::Any(guessed.isEmpty() ? AVMEDIA_MIMETYPE_COMMON : guessed));
473 xStreamProps->setPropertyValue( // turn off compression
474 u"Compressed"_ustr, uno::Any(false));
476 return xStream;
480 bool EmbedMedia(uno::Reference<frame::XModel> const& xModel,
481 OUString const& rSourceURL, OUString & o_rEmbeddedURL, uno::Reference<io::XInputStream> const& xInputStream)
485 uno::Reference<document::XStorageBasedDocument> const xSBD(xModel,
486 uno::UNO_QUERY_THROW);
487 uno::Reference<embed::XStorage> const xStorage(
488 xSBD->getDocumentStorage(), uno::UNO_SET_THROW);
490 static constexpr OUString media(u"Media"_ustr);
491 uno::Reference<embed::XStorage> const xSubStorage(
492 xStorage->openStorageElement(media, embed::ElementModes::WRITE));
494 OUString filename(GetFilename(rSourceURL));
496 uno::Reference<io::XStream> const xStream(
497 CreateStream(xSubStorage, filename), uno::UNO_SET_THROW);
498 uno::Reference<io::XOutputStream> const xOutStream(
499 xStream->getOutputStream(), uno::UNO_SET_THROW);
501 if (xInputStream.is())
503 // Throw Exception if failed.
504 ::comphelper::OStorageHelper::CopyInputToOutput(xInputStream, xOutStream);
506 else
508 ::ucbhelper::Content sourceContent(rSourceURL,
509 uno::Reference<ucb::XCommandEnvironment>(),
510 comphelper::getProcessComponentContext());
512 if (!sourceContent.openStream(xOutStream)) // copy file to storage
514 SAL_INFO("avmedia", "openStream to storage failed");
515 return false;
519 uno::Reference<embed::XTransactedObject> const xSubTransaction(
520 xSubStorage, uno::UNO_QUERY);
521 if (xSubTransaction.is()) {
522 xSubTransaction->commit();
524 uno::Reference<embed::XTransactedObject> const xTransaction(
525 xStorage, uno::UNO_QUERY);
526 if (xTransaction.is()) {
527 xTransaction->commit();
530 o_rEmbeddedURL = "vnd.sun.star.Package:" + media + "/" + filename;
531 return true;
533 catch (uno::Exception const&)
535 SAL_WARN("avmedia",
536 "Exception while trying to embed media");
538 return false;
541 bool CreateMediaTempFile(uno::Reference<io::XInputStream> const& xInStream,
542 OUString& o_rTempFileURL, std::u16string_view rDesiredExtension)
544 OUString tempFileURL;
545 ::osl::FileBase::RC const err =
546 ::osl::FileBase::createTempFile(nullptr, nullptr, & tempFileURL);
547 if (::osl::FileBase::E_None != err)
549 SAL_WARN("avmedia", "cannot create temp file");
550 return false;
553 if (!rDesiredExtension.empty())
555 OUString newTempFileURL = tempFileURL + rDesiredExtension;
556 if (osl::File::move(tempFileURL, newTempFileURL) != osl::FileBase::E_None)
558 SAL_WARN("avmedia", "Could not rename file '" << tempFileURL << "' to '" << newTempFileURL << "'");
559 return false;
561 tempFileURL = newTempFileURL;
566 ::ucbhelper::Content tempContent(tempFileURL,
567 uno::Reference<ucb::XCommandEnvironment>(),
568 comphelper::getProcessComponentContext());
569 tempContent.writeStream(xInStream, true); // copy stream to file
571 catch (uno::Exception const&)
573 TOOLS_WARN_EXCEPTION("avmedia", "");
574 return false;
576 o_rTempFileURL = tempFileURL;
577 return true;
580 MediaTempFile::~MediaTempFile()
582 ::osl::File::remove(m_TempFileURL);
585 } // namespace avmedia
587 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */