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 }