/*
* Copyright (C) 2010-2013 Groupement d'Intérêt Public pour l'Education Numérique en Afrique (GIP ENA)
*
* This file is part of Open-Sankoré.
*
* Open-Sankoré is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License,
* with a specific linking exception for the OpenSSL project's
* "OpenSSL" library (or with modified versions of it that use the
* same license as the "OpenSSL" library).
*
* Open-Sankoré is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Open-Sankoré. If not, see .
*/
#include "UBGraphicsGroupContainerItem.h"
#include "UBGraphicsMediaItem.h"
#include "UBGraphicsMediaItemDelegate.h"
#include "UBGraphicsScene.h"
#include "UBGraphicsDelegateFrame.h"
#include "document/UBDocumentProxy.h"
#include "core/UBApplication.h"
#include "board/UBBoardController.h"
#include "core/memcheck.h"
bool UBGraphicsMediaItem::sIsMutedByDefault = false;
UBGraphicsMediaItem::UBGraphicsMediaItem(const QUrl& pMediaFileUrl, QGraphicsItem *parent)
: UBGraphicsProxyWidget(parent)
, mVideoWidget(NULL)
, mAudioWidget(NULL)
, mMuted(sIsMutedByDefault)
, mMutedByUserAction(sIsMutedByDefault)
, mMediaFileUrl(pMediaFileUrl)
, mLinkedImage(NULL)
, mInitialPos(0)
{
update();
mMediaObject = new Phonon::MediaObject(this);
QString mediaPath = pMediaFileUrl.toString();
if ("" == mediaPath)
mediaPath = pMediaFileUrl.toLocalFile();
if (mediaPath.toLower().contains("videos"))
{
mMediaType = mediaType_Video;
mAudioOutput = new Phonon::AudioOutput(Phonon::VideoCategory, this);
mMediaObject->setTickInterval(50);
mVideoWidget = new Phonon::VideoWidget(); // owned and destructed by the scene ...
Phonon::createPath(mMediaObject, mVideoWidget);
if(mVideoWidget->sizeHint() == QSize(1,1)){
mVideoWidget->resize(320,240);
}
mVideoWidget->setMinimumSize(140,26);
haveLinkedImage = true;
}
else if (mediaPath.toLower().contains("audios")){
mMediaType = mediaType_Audio;
mAudioOutput = new Phonon::AudioOutput(Phonon::MusicCategory, this);
mMediaObject->setTickInterval(1000);
mAudioWidget = new QWidget();
mAudioWidget->resize(320,26);
mAudioWidget->setMinimumSize(150,26);
haveLinkedImage = false;
}
Phonon::createPath(mMediaObject, mAudioOutput);
mSource = Phonon::MediaSource(pMediaFileUrl);
mMediaObject->setCurrentSource(mSource);
// we should create delegate after media objects because delegate uses his properties at creation.
setDelegate(new UBGraphicsMediaItemDelegate(this, mMediaObject));
// delegate should be created earler because we setWidget calls resize event for graphics proxy widgt.
// resize uses delegate.
if (mediaType_Video == mMediaType)
setWidget(mVideoWidget);
else
setWidget(mAudioWidget);
// media widget should be created and placed on proxy widget here.
// TODO claudio remove this because in contrast with the fact the frame should be created on demand.
// but without forcing the control creation we do not have the frame and all the calculation
// for the different element of the interface will fail
Delegate()->createControls();
if (mediaType_Audio == mMediaType)
Delegate()->frame()->setOperationMode(UBGraphicsDelegateFrame::ResizingHorizontally);
else
Delegate()->frame()->setOperationMode(UBGraphicsDelegateFrame::Resizing);
setData(UBGraphicsItemData::itemLayerType, QVariant(itemLayerType::ObjectItem)); //Necessary to set if we want z value to be assigned correctly
connect(Delegate(), SIGNAL(showOnDisplayChanged(bool)), this, SLOT(showOnDisplayChanged(bool)));
connect(mMediaObject, SIGNAL(hasVideoChanged(bool)), this, SLOT(hasMediaChanged(bool)));
}
UBGraphicsMediaItem::~UBGraphicsMediaItem()
{
if (mMediaObject)
mMediaObject->stop();
}
QVariant UBGraphicsMediaItem::itemChange(GraphicsItemChange change, const QVariant &value)
{
if ((change == QGraphicsItem::ItemEnabledChange)
|| (change == QGraphicsItem::ItemSceneChange)
|| (change == QGraphicsItem::ItemVisibleChange))
{
if (mMediaObject && (!isEnabled() || !isVisible() || !scene()))
mMediaObject->pause();
}
else if (change == QGraphicsItem::ItemSceneHasChanged)
{
if (!scene())
mMediaObject->stop();
else {
QString absoluteMediaFilename;
if(mMediaFileUrl.toLocalFile().startsWith("audios/") || mMediaFileUrl.toLocalFile().startsWith("videos/"))
absoluteMediaFilename = scene()->document()->persistencePath() + "/" + mMediaFileUrl.toLocalFile();
else
absoluteMediaFilename = mMediaFileUrl.toLocalFile();
if (absoluteMediaFilename.length() > 0)
mMediaObject->setCurrentSource(Phonon::MediaSource(absoluteMediaFilename));
}
}
return UBGraphicsProxyWidget::itemChange(change, value);
}
void UBGraphicsMediaItem::setSourceUrl(const QUrl &pSourceUrl)
{
UBItem::setSourceUrl(pSourceUrl);
}
void UBGraphicsMediaItem::clearSource()
{
QString path = mediaFileUrl().toLocalFile();
//if path is absolute clean duplicated path string
if (!path.contains(UBApplication::boardController->selectedDocument()->persistencePath()))
path = UBApplication::boardController->selectedDocument()->persistencePath() + "/" + path;
if (!UBFileSystemUtils::deleteFile(path))
qDebug() << "cannot delete file: " << path;
}
void UBGraphicsMediaItem::toggleMute()
{
mMuted = !mMuted;
setMute(mMuted);
}
void UBGraphicsMediaItem::setMute(bool bMute)
{
mMuted = bMute;
mAudioOutput->setMuted(mMuted);
mMutedByUserAction = mMuted;
sIsMutedByDefault = mMuted;
}
void UBGraphicsMediaItem::hasMediaChanged(bool hasMedia)
{
if(hasMedia && mMediaObject->isSeekable())
{
mMediaObject->seek(mInitialPos);
UBGraphicsMediaItemDelegate *med = dynamic_cast(Delegate());
if (med)
med->updateTicker(initialPos());
}
}
UBGraphicsScene* UBGraphicsMediaItem::scene()
{
return qobject_cast(QGraphicsItem::scene());
}
void UBGraphicsMediaItem::activeSceneChanged()
{
if (UBApplication::boardController->activeScene() != scene())
mMediaObject->pause();
}
void UBGraphicsMediaItem::showOnDisplayChanged(bool shown)
{
if (!shown)
{
mMuted = true;
mAudioOutput->setMuted(mMuted);
}
else if (!mMutedByUserAction)
{
mMuted = false;
mAudioOutput->setMuted(mMuted);
}
}
UBItem* UBGraphicsMediaItem::deepCopy() const
{
QUrl url = this->mediaFileUrl();
UBGraphicsMediaItem *copy = new UBGraphicsMediaItem(url, parentItem());
copy->setUuid(this->uuid()); // this is OK for now as long as Widgets are imutable
copyItemParameters(copy);
return copy;
}
void UBGraphicsMediaItem::copyItemParameters(UBItem *copy) const
{
UBGraphicsMediaItem *cp = dynamic_cast(copy);
if (cp)
{
cp->setPos(this->pos());
cp->setTransform(this->transform());
cp->setFlag(QGraphicsItem::ItemIsMovable, true);
cp->setFlag(QGraphicsItem::ItemIsSelectable, true);
cp->setData(UBGraphicsItemData::ItemLayerType, this->data(UBGraphicsItemData::ItemLayerType));
cp->setData(UBGraphicsItemData::ItemLocked, this->data(UBGraphicsItemData::ItemLocked));
cp->setSourceUrl(this->sourceUrl());
cp->resize(this->size());
connect(UBApplication::boardController, SIGNAL(activeSceneChanged()), cp, SLOT(activeSceneChanged()));
// TODO UB 4.7 complete all members
}
}
void UBGraphicsMediaItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
if (Delegate())
{
Delegate()->mousePressEvent(event);
if (parentItem() && UBGraphicsGroupContainerItem::Type == parentItem()->type())
{
UBGraphicsGroupContainerItem *group = qgraphicsitem_cast(parentItem());
if (group)
{
QGraphicsItem *curItem = group->getCurrentItem();
if (curItem && this != curItem)
group->deselectCurrentItem();
group->setCurrentItem(this);
this->setSelected(true);
Delegate()->positionHandles();
}
}
}
if (parentItem() && parentItem()->type() == UBGraphicsGroupContainerItem::Type) {
mShouldMove = false;
if (!Delegate()->mousePressEvent(event))
event->accept();
}
else {
mShouldMove = (event->buttons() & Qt::LeftButton);
mMousePressPos = event->scenePos();
mMouseMovePos = mMousePressPos;
event->accept();
setSelected(true);
}
}
void UBGraphicsMediaItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
if(mShouldMove && (event->buttons() & Qt::LeftButton))
{
QPointF offset = event->scenePos() - mMousePressPos;
if (offset.toPoint().manhattanLength() > QApplication::startDragDistance())
{
QPointF mouseMovePos = mapFromScene(mMouseMovePos);
QPointF eventPos = mapFromScene( event->scenePos());
QPointF translation = eventPos - mouseMovePos;
translate(translation.x(), translation.y());
}
mMouseMovePos = event->scenePos();
}
event->accept();
}