android: Update app-specific/MIME type icons
[LibreOffice.git] / avmedia / source / framework / mediaitem.cxx
blobf177c8bea687dc2f2b1c6e36402e96a08d50df02
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_Referer;
59 OUString m_sMimeType;
60 AVMediaSetMask m_nMaskSet;
61 MediaState m_eState;
62 double m_fTime;
63 double m_fDuration;
64 sal_Int16 m_nVolumeDB;
65 bool m_bLoop;
66 bool m_bMute;
67 css::media::ZoomLevel m_eZoom;
68 Graphic m_aGraphic;
69 text::GraphicCrop m_aCrop;
71 explicit Impl(AVMediaSetMask nMaskSet)
72 : m_nMaskSet( nMaskSet )
73 , m_eState( MediaState::Stop )
74 , m_fTime( 0.0 )
75 , m_fDuration( 0.0 )
76 , m_nVolumeDB( 0 )
77 , m_bLoop( false )
78 , m_bMute( false )
79 , m_eZoom( css::media::ZoomLevel_NOT_AVAILABLE )
85 MediaItem::MediaItem( sal_uInt16 i_nWhich, AVMediaSetMask nMaskSet )
86 : SfxPoolItem( i_nWhich )
87 , m_pImpl( new Impl(nMaskSet) )
92 MediaItem::MediaItem( const MediaItem& rItem )
93 : SfxPoolItem( rItem )
94 , m_pImpl( new Impl(*rItem.m_pImpl) )
99 MediaItem::~MediaItem()
104 bool MediaItem::operator==( const SfxPoolItem& rItem ) const
106 assert( SfxPoolItem::operator==(rItem));
107 MediaItem const& rOther(static_cast< const MediaItem& >(rItem));
108 return m_pImpl->m_nMaskSet == rOther.m_pImpl->m_nMaskSet
109 && m_pImpl->m_URL == rOther.m_pImpl->m_URL
110 && m_pImpl->m_Referer == rOther.m_pImpl->m_Referer
111 && m_pImpl->m_sMimeType == rOther.m_pImpl->m_sMimeType
112 && m_pImpl->m_aGraphic == rOther.m_pImpl->m_aGraphic
113 && m_pImpl->m_aCrop == rOther.m_pImpl->m_aCrop
114 && m_pImpl->m_eState == rOther.m_pImpl->m_eState
115 && m_pImpl->m_fDuration == rOther.m_pImpl->m_fDuration
116 && m_pImpl->m_fTime == rOther.m_pImpl->m_fTime
117 && m_pImpl->m_nVolumeDB == rOther.m_pImpl->m_nVolumeDB
118 && m_pImpl->m_bLoop == rOther.m_pImpl->m_bLoop
119 && m_pImpl->m_bMute == rOther.m_pImpl->m_bMute
120 && m_pImpl->m_eZoom == rOther.m_pImpl->m_eZoom;
123 MediaItem* MediaItem::Clone( SfxItemPool* ) const
125 return new MediaItem( *this );
128 bool MediaItem::GetPresentation( SfxItemPresentation,
129 MapUnit,
130 MapUnit,
131 OUString& rText,
132 const IntlWrapper& ) const
134 rText.clear();
135 return false;
138 bool MediaItem::QueryValue( css::uno::Any& rVal, sal_uInt8 ) const
140 uno::Sequence< uno::Any > aSeq{ uno::Any(m_pImpl->m_URL),
141 uno::Any(static_cast<sal_uInt32>(m_pImpl->m_nMaskSet)),
142 uno::Any(static_cast< sal_Int32 >( m_pImpl->m_eState )),
143 uno::Any(m_pImpl->m_fTime),
144 uno::Any(m_pImpl->m_fDuration),
145 uno::Any(m_pImpl->m_nVolumeDB),
146 uno::Any(m_pImpl->m_bLoop),
147 uno::Any(m_pImpl->m_bMute),
148 uno::Any(m_pImpl->m_eZoom),
149 uno::Any(m_pImpl->m_sMimeType) };
151 rVal <<= aSeq;
153 return true;
157 bool MediaItem::PutValue( const css::uno::Any& rVal, sal_uInt8 )
159 uno::Sequence< uno::Any > aSeq;
160 bool bRet = false;
162 if( ( rVal >>= aSeq ) && ( aSeq.getLength() == 10 ) )
164 sal_Int32 nInt32 = 0;
166 aSeq[ 0 ] >>= m_pImpl->m_URL;
167 aSeq[ 1 ] >>= nInt32;
168 m_pImpl->m_nMaskSet = static_cast<AVMediaSetMask>(nInt32);
169 aSeq[ 2 ] >>= nInt32;
170 m_pImpl->m_eState = static_cast< MediaState >( nInt32 );
171 aSeq[ 3 ] >>= m_pImpl->m_fTime;
172 aSeq[ 4 ] >>= m_pImpl->m_fDuration;
173 aSeq[ 5 ] >>= m_pImpl->m_nVolumeDB;
174 aSeq[ 6 ] >>= m_pImpl->m_bLoop;
175 aSeq[ 7 ] >>= m_pImpl->m_bMute;
176 aSeq[ 8 ] >>= m_pImpl->m_eZoom;
177 aSeq[ 9 ] >>= m_pImpl->m_sMimeType;
179 bRet = true;
182 return bRet;
185 bool MediaItem::merge(const MediaItem& rMediaItem)
187 bool bChanged = false;
189 const AVMediaSetMask nMaskSet = rMediaItem.getMaskSet();
191 if( AVMediaSetMask::URL & nMaskSet )
192 bChanged |= setURL(rMediaItem.getURL(), rMediaItem.getTempURL(), rMediaItem.getReferer());
194 if( AVMediaSetMask::MIME_TYPE & nMaskSet )
195 bChanged |= setMimeType(rMediaItem.getMimeType());
197 if (nMaskSet & AVMediaSetMask::GRAPHIC)
198 bChanged |= setGraphic(rMediaItem.getGraphic());
200 if (nMaskSet & AVMediaSetMask::CROP)
201 bChanged |= setCrop(rMediaItem.getCrop());
203 if( AVMediaSetMask::STATE & nMaskSet )
204 bChanged |= setState( rMediaItem.getState() );
206 if( AVMediaSetMask::DURATION & nMaskSet )
207 bChanged |= setDuration(rMediaItem.getDuration());
209 if( AVMediaSetMask::TIME & nMaskSet )
210 bChanged |= setTime(rMediaItem.getTime());
212 if( AVMediaSetMask::LOOP & nMaskSet )
213 bChanged |= setLoop(rMediaItem.isLoop());
215 if( AVMediaSetMask::MUTE & nMaskSet )
216 bChanged |= setMute(rMediaItem.isMute());
218 if( AVMediaSetMask::VOLUMEDB & nMaskSet )
219 bChanged |= setVolumeDB(rMediaItem.getVolumeDB());
221 if( AVMediaSetMask::ZOOM & nMaskSet )
222 bChanged |= setZoom(rMediaItem.getZoom());
224 return bChanged;
227 AVMediaSetMask MediaItem::getMaskSet() const
229 return m_pImpl->m_nMaskSet;
232 bool MediaItem::setURL(const OUString& rURL, const OUString& rTempURL, const OUString& rReferer)
234 m_pImpl->m_nMaskSet |= AVMediaSetMask::URL;
235 bool bChanged = rURL != m_pImpl->m_URL || rTempURL != m_pImpl->m_TempFileURL || rReferer != m_pImpl->m_Referer;
236 if (bChanged)
238 m_pImpl->m_URL = rURL;
239 m_pImpl->m_TempFileURL = rTempURL;
240 m_pImpl->m_Referer = rReferer;
241 setMimeType(::comphelper::GuessMediaMimeType(GetFilename(rURL)));
243 return bChanged;
246 const OUString& MediaItem::getURL() const
248 return m_pImpl->m_URL;
251 const OUString& MediaItem::getTempURL() const
253 return m_pImpl->m_TempFileURL;
256 const OUString& MediaItem::getReferer() const
258 return m_pImpl->m_Referer;
261 bool MediaItem::setMimeType(const OUString& rMimeType)
263 m_pImpl->m_nMaskSet |= AVMediaSetMask::MIME_TYPE;
264 bool bChanged = rMimeType != m_pImpl->m_sMimeType;
265 if (bChanged)
266 m_pImpl->m_sMimeType = rMimeType;
267 return bChanged;
270 OUString MediaItem::getMimeType() const
272 return !m_pImpl->m_sMimeType.isEmpty() ? m_pImpl->m_sMimeType : AVMEDIA_MIMETYPE_COMMON;
275 bool MediaItem::setGraphic(const Graphic& rGraphic)
277 m_pImpl->m_nMaskSet |= AVMediaSetMask::GRAPHIC;
278 bool bChanged = rGraphic != m_pImpl->m_aGraphic;
279 if (bChanged)
280 m_pImpl->m_aGraphic = rGraphic;
281 return bChanged;
284 const Graphic & MediaItem::getGraphic() const { return m_pImpl->m_aGraphic; }
286 bool MediaItem::setCrop(const text::GraphicCrop& rCrop)
288 m_pImpl->m_nMaskSet |= AVMediaSetMask::CROP;
289 bool bChanged = rCrop != m_pImpl->m_aCrop;
290 if (bChanged)
291 m_pImpl->m_aCrop = rCrop;
292 return bChanged;
295 const text::GraphicCrop& MediaItem::getCrop() const { return m_pImpl->m_aCrop; }
297 bool MediaItem::setState(MediaState eState)
299 m_pImpl->m_nMaskSet |= AVMediaSetMask::STATE;
300 bool bChanged = eState != m_pImpl->m_eState;
301 if (bChanged)
302 m_pImpl->m_eState = eState;
303 return bChanged;
306 MediaState MediaItem::getState() const
308 return m_pImpl->m_eState;
311 bool MediaItem::setDuration(double fDuration)
313 m_pImpl->m_nMaskSet |= AVMediaSetMask::DURATION;
314 bool bChanged = fDuration != m_pImpl->m_fDuration;
315 if (bChanged)
316 m_pImpl->m_fDuration = fDuration;
317 return bChanged;
320 double MediaItem::getDuration() const
322 return m_pImpl->m_fDuration;
325 bool MediaItem::setTime(double fTime)
327 m_pImpl->m_nMaskSet |= AVMediaSetMask::TIME;
328 bool bChanged = fTime != m_pImpl->m_fTime;
329 if (bChanged)
330 m_pImpl->m_fTime = fTime;
331 return bChanged;
334 double MediaItem::getTime() const
336 return m_pImpl->m_fTime;
339 bool MediaItem::setLoop(bool bLoop)
341 m_pImpl->m_nMaskSet |= AVMediaSetMask::LOOP;
342 bool bChanged = bLoop != m_pImpl->m_bLoop;
343 if (bChanged)
344 m_pImpl->m_bLoop = bLoop;
345 return bChanged;
348 bool MediaItem::isLoop() const
350 return m_pImpl->m_bLoop;
353 bool MediaItem::setMute(bool bMute)
355 m_pImpl->m_nMaskSet |= AVMediaSetMask::MUTE;
356 bool bChanged = bMute != m_pImpl->m_bMute;
357 if (bChanged)
358 m_pImpl->m_bMute = bMute;
359 return bChanged;
362 bool MediaItem::isMute() const
364 return m_pImpl->m_bMute;
367 bool MediaItem::setVolumeDB(sal_Int16 nDB)
369 m_pImpl->m_nMaskSet |= AVMediaSetMask::VOLUMEDB;
370 bool bChanged = nDB != m_pImpl->m_nVolumeDB;
371 if (bChanged)
372 m_pImpl->m_nVolumeDB = nDB;
373 return bChanged;
376 sal_Int16 MediaItem::getVolumeDB() const
378 return m_pImpl->m_nVolumeDB;
381 bool MediaItem::setZoom(css::media::ZoomLevel eZoom)
383 m_pImpl->m_nMaskSet |= AVMediaSetMask::ZOOM;
384 bool bChanged = eZoom != m_pImpl->m_eZoom;
385 if (bChanged)
386 m_pImpl->m_eZoom = eZoom;
387 return bChanged;
390 css::media::ZoomLevel MediaItem::getZoom() const
392 return m_pImpl->m_eZoom;
395 OUString GetFilename(OUString const& rSourceURL)
397 uno::Reference<uri::XUriReferenceFactory> const xUriFactory(
398 uri::UriReferenceFactory::create(
399 comphelper::getProcessComponentContext()));
400 uno::Reference<uri::XUriReference> const xSourceURI(
401 xUriFactory->parse(rSourceURL), uno::UNO_SET_THROW);
403 OUString filename;
405 sal_Int32 const nSegments(xSourceURI->getPathSegmentCount());
406 if (0 < nSegments)
408 filename = xSourceURI->getPathSegment(nSegments - 1);
411 if (!::comphelper::OStorageHelper::IsValidZipEntryFileName(
412 filename, false) || !filename.getLength())
414 filename = "media";
416 return filename;
420 uno::Reference<io::XStream>
421 CreateStream(uno::Reference<embed::XStorage> const& xStorage,
422 OUString const& rFilename)
424 OUString filename(rFilename);
426 if (xStorage->hasByName(filename))
428 std::u16string_view basename;
429 std::u16string_view suffix;
430 sal_Int32 const nIndex(rFilename.lastIndexOf('.'));
431 if (0 < nIndex)
433 basename = rFilename.subView(0, nIndex);
434 suffix = rFilename.subView(nIndex);
436 sal_Int32 count(0); // sigh... try to generate non-existent name
439 ++count;
440 filename = basename + OUString::number(count) + suffix;
442 while (xStorage->hasByName(filename));
445 uno::Reference<io::XStream> const xStream(
446 xStorage->openStreamElement(filename,
447 embed::ElementModes::WRITE | embed::ElementModes::TRUNCATE),
448 uno::UNO_SET_THROW);
449 uno::Reference< beans::XPropertySet > const xStreamProps(xStream,
450 uno::UNO_QUERY);
451 if (xStreamProps.is()) { // this is NOT supported in FileSystemStorage
452 OUString const guessed(::comphelper::GuessMediaMimeType(filename));
453 xStreamProps->setPropertyValue("MediaType",
454 uno::Any(guessed.isEmpty() ? AVMEDIA_MIMETYPE_COMMON : guessed));
455 xStreamProps->setPropertyValue( // turn off compression
456 "Compressed", uno::Any(false));
458 return xStream;
462 bool EmbedMedia(uno::Reference<frame::XModel> const& xModel,
463 OUString const& rSourceURL, OUString & o_rEmbeddedURL, uno::Reference<io::XInputStream> const& xInputStream)
467 uno::Reference<document::XStorageBasedDocument> const xSBD(xModel,
468 uno::UNO_QUERY_THROW);
469 uno::Reference<embed::XStorage> const xStorage(
470 xSBD->getDocumentStorage(), uno::UNO_SET_THROW);
472 OUString const media("Media");
473 uno::Reference<embed::XStorage> const xSubStorage(
474 xStorage->openStorageElement(media, embed::ElementModes::WRITE));
476 OUString filename(GetFilename(rSourceURL));
478 uno::Reference<io::XStream> const xStream(
479 CreateStream(xSubStorage, filename), uno::UNO_SET_THROW);
480 uno::Reference<io::XOutputStream> const xOutStream(
481 xStream->getOutputStream(), uno::UNO_SET_THROW);
483 if (xInputStream.is())
485 // Throw Exception if failed.
486 ::comphelper::OStorageHelper::CopyInputToOutput(xInputStream, xOutStream);
488 else
490 ::ucbhelper::Content sourceContent(rSourceURL,
491 uno::Reference<ucb::XCommandEnvironment>(),
492 comphelper::getProcessComponentContext());
494 if (!sourceContent.openStream(xOutStream)) // copy file to storage
496 SAL_INFO("avmedia", "openStream to storage failed");
497 return false;
501 uno::Reference<embed::XTransactedObject> const xSubTransaction(
502 xSubStorage, uno::UNO_QUERY);
503 if (xSubTransaction.is()) {
504 xSubTransaction->commit();
506 uno::Reference<embed::XTransactedObject> const xTransaction(
507 xStorage, uno::UNO_QUERY);
508 if (xTransaction.is()) {
509 xTransaction->commit();
512 o_rEmbeddedURL = "vnd.sun.star.Package:" + media + "/" + filename;
513 return true;
515 catch (uno::Exception const&)
517 SAL_WARN("avmedia",
518 "Exception while trying to embed media");
520 return false;
523 bool CreateMediaTempFile(uno::Reference<io::XInputStream> const& xInStream,
524 OUString& o_rTempFileURL, std::u16string_view rDesiredExtension)
526 OUString tempFileURL;
527 ::osl::FileBase::RC const err =
528 ::osl::FileBase::createTempFile(nullptr, nullptr, & tempFileURL);
529 if (::osl::FileBase::E_None != err)
531 SAL_WARN("avmedia", "cannot create temp file");
532 return false;
535 if (!rDesiredExtension.empty())
537 OUString newTempFileURL = tempFileURL + rDesiredExtension;
538 if (osl::File::move(tempFileURL, newTempFileURL) != osl::FileBase::E_None)
540 SAL_WARN("avmedia", "Could not rename file '" << tempFileURL << "' to '" << newTempFileURL << "'");
541 return false;
543 tempFileURL = newTempFileURL;
548 ::ucbhelper::Content tempContent(tempFileURL,
549 uno::Reference<ucb::XCommandEnvironment>(),
550 comphelper::getProcessComponentContext());
551 tempContent.writeStream(xInStream, true); // copy stream to file
553 catch (uno::Exception const&)
555 TOOLS_WARN_EXCEPTION("avmedia", "");
556 return false;
558 o_rTempFileURL = tempFileURL;
559 return true;
562 MediaTempFile::~MediaTempFile()
564 ::osl::File::remove(m_TempFileURL);
567 } // namespace avmedia
569 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */