Commit 1fd2f7bf authored by Jean-Baptiste Mardelle's avatar Jean-Baptiste Mardelle
Browse files

Titler: add warning about missing elements with button to delete them

parent 436cc318
......@@ -70,9 +70,6 @@ KdenliveSettingsDialog::KdenliveSettingsDialog(const QMap<QString, QString> &map
m_page1 = addPage(p1, i18n("Misc"));
m_page1->setIcon(QIcon::fromTheme(QStringLiteral("configure")));
// Hide avformat-novalidate trick, causes crash (bug #2205 and #2206)
m_configMisc.kcfg_projectloading_avformatnovalidate->setVisible(false);
m_configMisc.kcfg_use_exiftool->setEnabled(!QStandardPaths::findExecutable(QStringLiteral("exiftool")).isEmpty());
QWidget *p8 = new QWidget;
......
......@@ -68,6 +68,7 @@ TitleDocument::TitleDocument()
m_scene = nullptr;
m_width = 0;
m_height = 0;
m_missingElements = 0;
}
void TitleDocument::setScene(QGraphicsScene *_scene, int width, int height)
......@@ -365,6 +366,7 @@ bool TitleDocument::saveDocument(const QUrl &url, QGraphicsRectItem *startv, QGr
int TitleDocument::loadFromXml(const QDomDocument &doc, QGraphicsRectItem *startv, QGraphicsRectItem *endv, int *duration, const QString &projectpath)
{
m_projectPath = projectpath;
m_missingElements = 0;
QDomNodeList titles = doc.elementsByTagName(QStringLiteral("kdenlivetitle"));
// TODO: Check if the opened title size is equal to project size, otherwise warn user and rescale
if (doc.documentElement().hasAttribute(QStringLiteral("width")) && doc.documentElement().hasAttribute(QStringLiteral("height"))) {
......@@ -535,15 +537,21 @@ int TitleDocument::loadFromXml(const QDomDocument &doc, QGraphicsRectItem *start
QString url = itemNode.namedItem(QStringLiteral("content")).attributes().namedItem(QStringLiteral("url")).nodeValue();
QString base64 = itemNode.namedItem(QStringLiteral("content")).attributes().namedItem(QStringLiteral("base64")).nodeValue();
QPixmap pix;
bool missing = false;
if (base64.isEmpty()) {
pix.load(url);
if (pix.isNull()) {
pix = createInvalidPixmap(url);
m_missingElements++;
missing = true;
}
} else {
pix.loadFromData(QByteArray::fromBase64(base64.toLatin1()));
}
auto *rec = new MyPixmapItem(pix);
if (missing) {
rec->setData(Qt::UserRole + 2, 1);
}
m_scene->addItem(rec);
rec->setShapeMode(QGraphicsPixmapItem::BoundingRectShape);
rec->setData(Qt::UserRole, url);
......@@ -575,7 +583,9 @@ int TitleDocument::loadFromXml(const QDomDocument &doc, QGraphicsRectItem *start
gitem = rec;
} else {
QPixmap pix = createInvalidPixmap(url);
m_missingElements++;
auto *rec2 = new MyPixmapItem(pix);
rec2->setData(Qt::UserRole + 2, 1);
m_scene->addItem(rec2);
rec2->setShapeMode(QGraphicsPixmapItem::BoundingRectShape);
rec2->setData(Qt::UserRole, url);
......@@ -647,6 +657,11 @@ int TitleDocument::loadFromXml(const QDomDocument &doc, QGraphicsRectItem *start
return maxZValue;
}
int TitleDocument::invalidCount() const
{
return m_missingElements;
}
QPixmap TitleDocument::createInvalidPixmap(const QString &url)
{
int missingHeight = m_height / 10;
......
......@@ -45,6 +45,8 @@ public:
int frameHeight() const;
/** \brief Extract embedded images in project titles folder. */
static const QString extractBase64Image(const QString &titlePath, const QString &data);
/** \brief The number of missing elements in this title. */
int invalidCount() const;
enum ItemOrigin { OriginXLeft = 0, OriginYTop = 1 };
enum AxisPosition { AxisDefault = 0, AxisInverted = 1 };
......@@ -52,6 +54,7 @@ public:
private:
QGraphicsScene *m_scene;
QString m_projectPath;
int m_missingElements;
int m_width;
int m_height;
QString colorToString(const QColor &);
......
......@@ -29,6 +29,7 @@
#include <KRecentDirs>
#include <klocalizedstring.h>
#include <kns3/downloaddialog.h>
#include <KMessageWidget>
#include "kdenlive_debug.h"
#include <QCryptographicHash>
......@@ -84,6 +85,7 @@ TitleWidget::TitleWidget(const QUrl &url, const Timecode &tc, const QString &pro
, m_startViewport(nullptr)
, m_endViewport(nullptr)
, m_count(0)
, m_missingMessage(nullptr)
, m_unicodeDialog(new UnicodeDialog(UnicodeDialog::InputHex))
, m_projectTitlePath(projectTitlePath)
, m_tc(tc)
......@@ -1993,8 +1995,24 @@ void TitleWidget::setXml(const QDomDocument &doc, const QString &id)
{
m_clipId = id;
int duration;
if (m_missingMessage) {
delete m_missingMessage;
m_missingMessage = nullptr;
}
m_count = m_titledocument.loadFromXml(doc, m_startViewport, m_endViewport, &duration, m_projectTitlePath);
adjustFrameSize();
if (m_titledocument.invalidCount() > 0) {
m_missingMessage = new KMessageWidget(this);
m_missingMessage->setCloseButtonVisible(true);
m_missingMessage->setWordWrap(true);
m_missingMessage->setMessageType(KMessageWidget::Warning);
m_missingMessage->setText(i18n("This title has %1 missing elements", m_titledocument.invalidCount()));
QAction *action = new QAction(i18n("Delete missing elements"));
m_missingMessage->addAction(action);
connect(action, &QAction::triggered, this, &TitleWidget::deleteMissingItems);
messageLayout->addWidget(m_missingMessage);
m_missingMessage->animatedShow();
}
title_duration->setText(m_tc.getTimecode(GenTime(duration, m_fps)));
/*if (doc.documentElement().hasAttribute("out")) {
GenTime duration = GenTime(doc.documentElement().attribute("out").toDouble() / 1000.0);
......@@ -2069,6 +2087,29 @@ void TitleWidget::slotAccepted()
writeChoices();
}
void TitleWidget::deleteMissingItems()
{
m_missingMessage->animatedHide();
QList<QGraphicsItem *> items = graphicsView->scene()->items();
QList<QGraphicsItem *> toDelete;
for (int i = 0; i < items.count(); ++i) {
if (items.at(i)->data(Qt::UserRole + 2).toInt() == 1) {
// We found a missing item
toDelete << items.at(i);
}
}
if (toDelete.size() != m_titledocument.invalidCount()) {
qDebug()<<"/// WARNING, INCOHERENT MISSING ELEMENTS in title: "<<toDelete.size()<<" != "<<m_titledocument.invalidCount();
}
while (!toDelete.isEmpty()) {
QGraphicsItem *item = toDelete.takeFirst();
if (m_scene) {
m_scene->removeItem(item);
}
}
m_missingMessage->deleteLater();
}
void TitleWidget::writeChoices()
{
// Get a pointer to a shared configuration instance, then get the TitleWidget group.
......
......@@ -28,7 +28,7 @@
#include <QSignalMapper>
class Monitor;
class KMessageWidget;
class TitleTemplate
{
public:
......@@ -118,6 +118,7 @@ private:
int m_count;
/** @brief Dialog for entering Unicode characters in text fields. */
UnicodeDialog *m_unicodeDialog;
KMessageWidget *m_missingMessage;
/** @brief Project path for storing title documents. */
QString m_projectTitlePath;
......@@ -369,6 +370,8 @@ private slots:
void templateIndexChanged(int);
void slotEditGradient();
void slotUpdateShadow();
/** @brief Remove missing items from the scene. */
void deleteMissingItems();
signals:
void requestBackgroundFrame(const QString &clipId, bool request);
......
......@@ -6,26 +6,40 @@
<rect>
<x>0</x>
<y>0</y>
<width>467</width>
<height>578</height>
<width>414</width>
<height>546</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="7" column="0" colspan="3">
<widget class="QCheckBox" name="kcfg_use_exiftool">
<property name="text">
<string>Get clip metadata with exiftool</string>
</property>
</widget>
</item>
<item row="5" column="0" colspan="3">
<widget class="QCheckBox" name="kcfg_disable_effect_parameters">
<widget class="QCheckBox" name="kcfg_automultistreams">
<property name="text">
<string>Disable parameters when the effect is disabled</string>
<string>Automatically import all streams in multi stream clips</string>
</property>
</widget>
</item>
<item row="8" column="0" colspan="3">
<widget class="QCheckBox" name="kcfg_use_exiftool">
<widget class="QCheckBox" name="kcfg_use_magicLantern">
<property name="text">
<string>Get clip metadata with exiftool</string>
<string>Get clip metadata created by Magic Lantern</string>
</property>
</widget>
</item>
<item row="11" column="0" colspan="3">
<item row="4" column="0" colspan="3">
<widget class="QCheckBox" name="kcfg_disable_effect_parameters">
<property name="text">
<string>Disable parameters when the effect is disabled</string>
</property>
</widget>
</item>
<item row="10" column="0" colspan="3">
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Default Durations</string>
......@@ -84,41 +98,14 @@
</layout>
</widget>
</item>
<item row="4" column="0" colspan="3">
<widget class="QCheckBox" name="kcfg_projectloading_avformatnovalidate">
<property name="text">
<string>Do not validate the video files when loading a project (faster)</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="kcfg_crashrecovery">
<property name="text">
<string>Activate crash recovery (auto save)</string>
</property>
</widget>
</item>
<item row="12" column="0" colspan="3">
<widget class="QCheckBox" name="kcfg_autoimagesequence">
<item row="9" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Automatically import image sequences</string>
<string>Tab position</string>
</property>
</widget>
</item>
<item row="13" column="1">
<spacer>
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="10" column="1">
<item row="9" column="1">
<widget class="QComboBox" name="kcfg_tabposition">
<item>
<property name="text">
......@@ -142,7 +129,14 @@
</item>
</widget>
</item>
<item row="10" column="2">
<item row="11" column="0" colspan="3">
<widget class="QCheckBox" name="kcfg_autoimagesequence">
<property name="text">
<string>Automatically import image sequences</string>
</property>
</widget>
</item>
<item row="9" column="2">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
......@@ -155,52 +149,51 @@
</property>
</spacer>
</item>
<item row="2" column="0" colspan="3">
<widget class="QCheckBox" name="kcfg_checkfirstprojectclip">
<item row="6" column="0" colspan="3">
<widget class="QCheckBox" name="kcfg_bypasscodeccheck">
<property name="text">
<string>Check if first added clip matches project profile</string>
<string>Bypass codec verification</string>
</property>
</widget>
</item>
<item row="0" column="0" colspan="3">
<widget class="QCheckBox" name="kcfg_openlastproject">
<property name="text">
<string>Open last project on startup</string>
<item row="12" column="1">
<spacer>
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item row="3" column="0" colspan="3">
<widget class="QCheckBox" name="kcfg_usekuiserver">
<property name="text">
<string>Use KDE job tracking for render jobs</string>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</widget>
</spacer>
</item>
<item row="7" column="0" colspan="3">
<widget class="QCheckBox" name="kcfg_bypasscodeccheck">
<item row="1" column="0">
<widget class="QCheckBox" name="kcfg_crashrecovery">
<property name="text">
<string>Bypass codec verification</string>
<string>Activate crash recovery (auto save)</string>
</property>
</widget>
</item>
<item row="10" column="0">
<widget class="QLabel" name="label_4">
<item row="2" column="0" colspan="3">
<widget class="QCheckBox" name="kcfg_checkfirstprojectclip">
<property name="text">
<string>Tab position</string>
<string>Check if first added clip matches project profile</string>
</property>
</widget>
</item>
<item row="6" column="0" colspan="3">
<widget class="QCheckBox" name="kcfg_automultistreams">
<item row="3" column="0" colspan="3">
<widget class="QCheckBox" name="kcfg_usekuiserver">
<property name="text">
<string>Automatically import all streams in multi stream clips</string>
<string>Use KDE job tracking for render jobs</string>
</property>
</widget>
</item>
<item row="9" column="0" colspan="3">
<widget class="QCheckBox" name="kcfg_use_magicLantern">
<item row="0" column="0" colspan="3">
<widget class="QCheckBox" name="kcfg_openlastproject">
<property name="text">
<string>Get clip metadata created by Magic Lantern</string>
<string>Open last project on startup</string>
</property>
</widget>
</item>
......
......@@ -41,39 +41,34 @@
<property name="bottomMargin">
<number>0</number>
</property>
<item row="0" column="0">
<widget class="QPushButton" name="origin_x_left">
<item row="0" column="13">
<widget class="QLabel" name="label_12">
<property name="text">
<string>+X</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>false</bool>
<string>Z-Index:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="value_x">
<property name="minimum">
<number>-5000</number>
</property>
<property name="maximum">
<number>5000</number>
<item row="0" column="12">
<widget class="QToolButton" name="zBottom">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QPushButton" name="origin_y_top">
<item row="0" column="4">
<widget class="QLabel" name="lWidth">
<property name="text">
<string>+Y</string>
<string>W</string>
</property>
<property name="checkable">
<bool>true</bool>
</widget>
</item>
<item row="0" column="7">
<widget class="QSpinBox" name="value_h">
<property name="minimum">
<number>-1000</number>
</property>
<property name="checked">
<bool>false</bool>
<property name="maximum">
<number>5000</number>
</property>
</widget>
</item>
......@@ -87,20 +82,16 @@
</property>
</widget>
</item>
<item row="0" column="4">
<widget class="QLabel" name="lWidth">
<item row="0" column="0">
<widget class="QPushButton" name="origin_x_left">
<property name="text">
<string>W</string>
<string>+X</string>
</property>
</widget>
</item>
<item row="0" column="7">
<widget class="QSpinBox" name="value_h">
<property name="minimum">
<number>-1000</number>
<property name="checkable">
<bool>true</bool>
</property>
<property name="maximum">
<number>5000</number>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
......@@ -114,10 +105,20 @@
</property>
</widget>
</item>
<item row="0" column="6">
<widget class="QLabel" name="label_19">
<item row="0" column="9">
<widget class="QToolButton" name="zUp">
<property name="text">
<string>H</string>
<string/>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="value_x">
<property name="minimum">
<number>-5000</number>
</property>
<property name="maximum">
<number>5000</number>
</property>
</widget>
</item>
......@@ -134,20 +135,6 @@
</property>
</spacer>
</item>
<item row="0" column="9">
<widget class="QToolButton" name="zUp">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="0" column="10">
<widget class="QToolButton" name="zDown">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="0" column="11">
<widget class="QToolButton" name="zTop">
<property name="text">
......@@ -155,10 +142,16 @@
</property>
</widget>
</item>
<item row="0" column="12">
<widget class="QToolButton" name="zBottom">
<item row="0" column="2">
<widget class="QPushButton" name="origin_y_top">
<property name="text">
<string/>
<string>+Y</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
......@@ -172,10 +165,17 @@
</property>
</widget>
</item>
<item row="0" column="13">
<widget class="QLabel" name="label_12">
<item row="0" column="10">
<widget class="QToolButton" name="zDown">
<property name="text">
<string>Z-Index:</string>
<string/>
</property>
</widget>
</item>
<item row="0" column="6">
<widget class="QLabel" name="label_19">
<property name="text">
<string>H</string>
</property>
</widget>
</item>
......@@ -333,38 +333,11 @@
<enum>Qt::Horizontal</enum>
</property>
<widget class="QWidget" name="verticalLayoutWidget">
<layout class="QGridLayout" name="gridLayout_16" rowstretch="0,0,0">
<layout class="QGridLayout" name="gridLayout_16" rowstretch="0,0,0,0">
<property name="spacing">
<number>6</number>
</property>
<item row="2" column="9">
<widget class="KColorButton" name="guideColor">
<property name="enabled">
<bool>false</bool>
</property>
<property name="autoDefault">
<bool>true</bool>
</property>
<property name="flat">
<bool>false</bool>
</property>
<property name="color">
<color>
<red>255</red>
<green>0</green>
<blue>0</blue>
</color>
</property>
<property name="defaultColor">
<color>
<red>255</red>
<green>0</green>
<blue>0</blue>
</color>
</property>
</widget>
</item>
<item row="2" column="2">
<item row="3" column="2">
<widget class="QToolButton" name="buttonUnselectAll">
<property name="enabled">
<bool>false</bool>
......@@ -374,14 +347,17 @@
</property>
</widget>
</item>
<item row="2" column="5">
<widget class="QCheckBox" name="use_grid">
<item row="3" column="0">
<widget class="QToolButton" name="buttonSelectImages">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Use grid</string>
<string>I</string>
</property>
</widget>
</item>
<item row="2" column="10">
<item row="3" column="10">
<spacer name="spacerBottomStack">
<property name="orientation">
<enum>Qt::Horizontal</enum>
......@@ -394,7 +370,7 @@
</property>
</spacer>
</item>
<item row="0" column="0" colspan="11">
<item row="1" column="0" colspan="11">
<widget class="QGraphicsView" name="graphicsView">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
......@@ -404,82 +380,113 @@
</property>
</widget>
</item>
<item row="2" column="3">
<widget class="QToolButton" name="buttonSelectAll">
<property name="whatsThis">
<string>Selects all items on the canvas.</string>
</property>
<item row="3" column="5">
<widget class="QCheckBox" name="use_grid">
<property name="text">
<string>A</string>
<string>Use grid</string>