File indexing completed on 2024-04-21 04:51:16

0001 /*
0002 SPDX-FileCopyrightText: 2015 Jean-Baptiste Mardelle <jb@kdenlive.org>
0003 This file is part of Kdenlive. See www.kdenlive.org.
0004 
0005 SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0006 */
0007 
0008 #include "projectsubclip.h"
0009 #include "bincommands.h"
0010 #include "core.h"
0011 #include "doc/docundostack.hpp"
0012 #include "doc/kdenlivedoc.h"
0013 #include "jobs/cachetask.h"
0014 #include "jobs/cliploadtask.h"
0015 #include "projectclip.h"
0016 #include "projectitemmodel.h"
0017 #include "utils/thumbnailcache.hpp"
0018 
0019 #include <KLocalizedString>
0020 #include <QDomElement>
0021 #include <QPainter>
0022 #include <QtMath>
0023 #include <utility>
0024 
0025 class ClipController;
0026 
0027 ProjectSubClip::ProjectSubClip(const QString &id, const std::shared_ptr<ProjectClip> &parent, const std::shared_ptr<ProjectItemModel> &model, int in, int out,
0028                                const QString &timecode, const QMap<QString, QString> &zoneProperties)
0029     : AbstractProjectItem(AbstractProjectItem::SubClipItem, id, model)
0030     , m_masterClip(parent)
0031 {
0032     m_inPoint = in;
0033     m_outPoint = out;
0034     m_duration = timecode;
0035     m_parentDuration = int(m_masterClip->frameDuration());
0036     m_parentClipId = m_masterClip->clipId();
0037     m_date = parent->date.addSecs(in);
0038     QPixmap pix(64, 36);
0039     pix.fill(Qt::lightGray);
0040     m_thumbnail = QIcon(pix);
0041     m_name = zoneProperties.value(QLatin1String("name"));
0042     if (m_name.isEmpty()) {
0043         m_name = i18n("Zone %1", parent->childCount() + 1);
0044     }
0045     m_rating = zoneProperties.value(QLatin1String("rating")).toUInt();
0046     m_tags = zoneProperties.value(QLatin1String("tags"));
0047     qDebug() << "=== LOADING SUBCLIP WITH RATING: " << m_rating << ", TAGS: " << m_tags;
0048     m_clipStatus = FileStatus::StatusReady;
0049     ClipLoadTask::start(ObjectId(KdenliveObjectType::BinClip, m_parentClipId.toInt(), QUuid()), QDomElement(), true, in, out, this);
0050 }
0051 
0052 std::shared_ptr<ProjectSubClip> ProjectSubClip::construct(const QString &id, const std::shared_ptr<ProjectClip> &parent,
0053                                                           const std::shared_ptr<ProjectItemModel> &model, int in, int out, const QString &timecode,
0054                                                           const QMap<QString, QString> &zoneProperties)
0055 {
0056     std::shared_ptr<ProjectSubClip> self(new ProjectSubClip(id, parent, model, in, out, timecode, zoneProperties));
0057     baseFinishConstruct(self);
0058     return self;
0059 }
0060 
0061 ProjectSubClip::~ProjectSubClip()
0062 {
0063     // controller is deleted in bincontroller
0064 }
0065 
0066 const QString ProjectSubClip::cutClipId() const
0067 {
0068     return QString("%1/%2/%3").arg(m_parentClipId).arg(m_inPoint).arg(m_outPoint);
0069 }
0070 
0071 void ProjectSubClip::gotThumb(int pos, const QImage &img)
0072 {
0073     if (pos == m_inPoint) {
0074         setThumbnail(img);
0075         disconnect(m_masterClip.get(), &ProjectClip::thumbReady, this, &ProjectSubClip::gotThumb);
0076     }
0077 }
0078 
0079 QString ProjectSubClip::getToolTip() const
0080 {
0081     return QString("%1-%2").arg(m_inPoint).arg(m_outPoint);
0082 }
0083 
0084 std::shared_ptr<ProjectClip> ProjectSubClip::clip(const QString &id)
0085 {
0086     Q_UNUSED(id);
0087     return std::shared_ptr<ProjectClip>();
0088 }
0089 
0090 std::shared_ptr<ProjectFolder> ProjectSubClip::folder(const QString &id)
0091 {
0092     Q_UNUSED(id);
0093     return std::shared_ptr<ProjectFolder>();
0094 }
0095 
0096 void ProjectSubClip::setBinEffectsEnabled(bool) {}
0097 
0098 GenTime ProjectSubClip::duration() const
0099 {
0100     // TODO
0101     return {};
0102 }
0103 
0104 QPoint ProjectSubClip::zone() const
0105 {
0106     return {m_inPoint, m_outPoint};
0107 }
0108 
0109 std::shared_ptr<ProjectClip> ProjectSubClip::clipAt(int ix)
0110 {
0111     Q_UNUSED(ix);
0112     return std::shared_ptr<ProjectClip>();
0113 }
0114 
0115 QDomElement ProjectSubClip::toXml(QDomDocument &document, bool, bool)
0116 {
0117     QDomElement sub = document.createElement(QStringLiteral("subclip"));
0118     sub.setAttribute(QStringLiteral("id"), m_masterClip->AbstractProjectItem::clipId());
0119     sub.setAttribute(QStringLiteral("in"), m_inPoint);
0120     sub.setAttribute(QStringLiteral("out"), m_outPoint);
0121     return sub;
0122 }
0123 
0124 std::shared_ptr<ProjectSubClip> ProjectSubClip::subClip(int in, int out)
0125 {
0126     if (m_inPoint == in && m_outPoint == out) {
0127         return std::static_pointer_cast<ProjectSubClip>(shared_from_this());
0128     }
0129     return std::shared_ptr<ProjectSubClip>();
0130 }
0131 
0132 void ProjectSubClip::setThumbnail(const QImage &img)
0133 {
0134     if (img.isNull()) {
0135         return;
0136     }
0137     QPixmap thumb = roundedPixmap(QPixmap::fromImage(img));
0138     int duration = m_parentDuration;
0139     double factor = double(thumb.width()) / duration;
0140     int zoneOut = m_outPoint - duration;
0141     QRect zoneRect(0, 0, thumb.width(), thumb.height());
0142     zoneRect.adjust(0, int(zoneRect.height() * 0.9), 0, int(-zoneRect.height() * 0.05));
0143     QPainter painter(&thumb);
0144     painter.fillRect(zoneRect, Qt::darkGreen);
0145     zoneRect.adjust(int(m_inPoint * factor), 0, int(zoneOut * factor), 0);
0146     painter.fillRect(zoneRect, Qt::green);
0147     painter.end();
0148     m_thumbnail = QIcon(thumb);
0149     if (auto ptr = m_model.lock())
0150         std::static_pointer_cast<ProjectItemModel>(ptr)->onItemUpdated(std::static_pointer_cast<ProjectSubClip>(shared_from_this()),
0151                                                                        {AbstractProjectItem::DataThumbnail});
0152 }
0153 
0154 QPixmap ProjectSubClip::thumbnail(int width, int height)
0155 {
0156     return m_thumbnail.pixmap(width, height);
0157 }
0158 
0159 bool ProjectSubClip::rename(const QString &name, int column)
0160 {
0161     // TODO refac: rework this
0162     Q_UNUSED(column)
0163     if (m_name == name) {
0164         return false;
0165     }
0166     // Rename folder
0167     auto *command = new RenameBinSubClipCommand(pCore->bin(), m_masterClip->clipId(), name, m_name, m_inPoint, m_outPoint);
0168     pCore->currentDoc()->commandStack()->push(command);
0169     return true;
0170 }
0171 
0172 std::shared_ptr<ProjectClip> ProjectSubClip::getMasterClip() const
0173 {
0174     return m_masterClip;
0175 }
0176 
0177 ClipType::ProducerType ProjectSubClip::clipType() const
0178 {
0179     return m_masterClip->clipType();
0180 }
0181 
0182 bool ProjectSubClip::hasAudioAndVideo() const
0183 {
0184     return m_masterClip->hasAudioAndVideo();
0185 }
0186 
0187 void ProjectSubClip::getThumbFromPercent(int percent)
0188 {
0189     // extract a maximum of 30 frames for bin preview
0190     if (percent < 0) {
0191         setThumbnail(ThumbnailCache::get()->getThumbnail(m_binId, m_inPoint));
0192         return;
0193     }
0194     int duration = m_outPoint - m_inPoint;
0195     int steps = qCeil(qMax(pCore->getCurrentFps(), double(duration) / 30));
0196     int framePos = duration * percent / 100;
0197     framePos -= framePos % steps;
0198     if (ThumbnailCache::get()->hasThumbnail(m_parentClipId, m_inPoint + framePos)) {
0199         setThumbnail(ThumbnailCache::get()->getThumbnail(m_parentClipId, m_inPoint + framePos));
0200     } else {
0201         // Generate percent thumbs
0202         CacheTask::start(ObjectId(KdenliveObjectType::BinClip, m_parentClipId.toInt(), QUuid()), 30, m_inPoint, m_outPoint, this);
0203     }
0204 }
0205 
0206 void ProjectSubClip::setProperties(const QMap<QString, QString> &properties)
0207 {
0208     bool propertyFound = false;
0209     if (properties.contains(QStringLiteral("kdenlive:tags"))) {
0210         propertyFound = true;
0211         m_tags = properties.value(QStringLiteral("kdenlive:tags"));
0212     }
0213     if (properties.contains(QStringLiteral("kdenlive:rating"))) {
0214         propertyFound = true;
0215         m_rating = properties.value(QStringLiteral("kdenlive:rating")).toUInt();
0216     }
0217     if (!propertyFound) {
0218         return;
0219     }
0220     if (auto ptr = m_model.lock()) {
0221         std::shared_ptr<AbstractProjectItem> parentItem = std::static_pointer_cast<ProjectItemModel>(ptr)->getItemByBinId(m_parentClipId);
0222         if (parentItem && parentItem->itemType() == AbstractProjectItem::ClipItem) {
0223             auto clipItem = std::static_pointer_cast<ProjectClip>(parentItem);
0224             clipItem->updateZones();
0225         }
0226     }
0227 }
0228 
0229 void ProjectSubClip::setRating(uint rating)
0230 {
0231     AbstractProjectItem::setRating(rating);
0232     if (auto ptr = m_model.lock()) {
0233         std::shared_ptr<AbstractProjectItem> parentItem = std::static_pointer_cast<ProjectItemModel>(ptr)->getItemByBinId(m_parentClipId);
0234         if (parentItem && parentItem->itemType() == AbstractProjectItem::ClipItem) {
0235             auto clipItem = std::static_pointer_cast<ProjectClip>(parentItem);
0236             clipItem->updateZones();
0237         }
0238     }
0239     pCore->currentDoc()->setModified(true);
0240 }