Commit 695306ae authored by Gary Wang's avatar Gary Wang Committed by Jean-Baptiste Mardelle
Browse files

Add the ability to export guides as chspters text

BUG: 449887
parent 421b1137
Pipeline #173444 passed with stage
in 6 minutes and 52 seconds
......@@ -8,6 +8,7 @@
#include "bin/projectclip.h"
#include "core.h"
#include "dialogs/markerdialog.h"
#include "dialogs/exportguidesdialog.h"
#include "doc/docundostack.hpp"
#include "kdenlivesettings.h"
#include "macros.hpp"
......@@ -651,3 +652,9 @@ bool MarkerListModel::editMarkerGui(const GenTime &pos, QWidget *parent, bool cr
}
return false;
}
void MarkerListModel::exportGuidesGui(QWidget *parent, GenTime projectDuration) const
{
QScopedPointer<ExportGuidesDialog> dialog(new ExportGuidesDialog(this, projectDuration, parent));
dialog->exec();
}
......@@ -131,6 +131,7 @@ public:
@return true if dialog was accepted and modification successful
*/
bool editMarkerGui(const GenTime &pos, QWidget *parent, bool createIfNotFound, ClipController *clip = nullptr, bool createOnly = false);
void exportGuidesGui(QWidget *parent, GenTime projectDuration) const;
// Mandatory overloads
QVariant data(const QModelIndex &index, int role) const override;
......
......@@ -4,6 +4,7 @@ set(kdenlive_SRCS
dialogs/encodingprofilesdialog.cpp
dialogs/kdenlivesettingsdialog.cpp
dialogs/markerdialog.cpp
dialogs/exportguidesdialog.cpp
dialogs/profilesdialog.cpp
dialogs/proxytest.cpp
dialogs/renderwidget.cpp
......
/*
SPDX-FileCopyrightText: 2022 Gary Wang <wzc782970009@gmail.com>
SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/
#include "exportguidesdialog.h"
#include "bin/model/markerlistmodel.hpp"
#include "core.h"
#include "kdenlive_debug.h"
#include <KMessageWidget>
#include <QFontDatabase>
#include <QPushButton>
#include <QClipboard>
#include <QTime>
#include "klocalizedstring.h"
#define YT_FORMAT "{{timecode}} {{comment}}"
ExportGuidesDialog::ExportGuidesDialog(const MarkerListModel *model, const GenTime duration, QWidget *parent)
: QDialog(parent)
, m_markerListModel(model)
, m_projectDuration(duration)
{
// setFont(QFontDatabase::systemFont(QFontDatabase::SmallestReadableFont));
setupUi(this);
setWindowTitle(i18n("Export guides as chapters description"));
const QString defaultFormat(YT_FORMAT);
formatEdit->setText(defaultFormat);
static std::array<QColor, 9> markerTypes = model->markerTypes;
QPixmap pixmap(32,32);
for (uint i = 1; i <= markerTypes.size(); ++i) {
pixmap.fill(markerTypes[size_t(i - 1)]);
QIcon colorIcon(pixmap);
markerTypeComboBox->addItem(colorIcon, i18n("Category %1", i - 1));
}
markerTypeComboBox->setCurrentIndex(0);
messageWidget->setText(i18n(
"If you are using the exported text for YouTube, you might want to check:\n"
"1. The start time of 00:00 must have a chapter.\n"
"2. There must be at least three timestamps in ascending order.\n"
"3. The minimum length for video chapters is 10 seconds."
));
messageWidget->setVisible(false);
updateContentByModel(defaultFormat, markerTypeComboBox->currentIndex() - 1);
QPushButton * btn = buttonBox->addButton(i18n("Copy to Clipboard"), QDialogButtonBox::ActionRole);
btn->setIcon(QIcon::fromTheme("edit-copy"));
connect(markerTypeComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, [this](int newIndex) {
updateContentByModel(formatEdit->text(), newIndex - 1);
});
connect(formatEdit, &QLineEdit::textEdited, this, [this]() {
updateContentByModel(formatEdit->text(), markerTypeComboBox->currentIndex() - 1);
});
connect(btn, &QAbstractButton::clicked, this, [this]() {
QClipboard *clipboard = QGuiApplication::clipboard();
clipboard->setText(this->generatedContent->toPlainText());
});
adjustSize();
}
ExportGuidesDialog::~ExportGuidesDialog()
{
}
void ExportGuidesDialog::updateContentByModel(const QString & format, int markerIndex) const
{
QStringList chapterTexts;
QList<CommentedTime> markers(m_markerListModel->getAllMarkers(markerIndex));
bool needCheck = format == YT_FORMAT;
bool needShowInfoMsg = false;
const int markerCount = markers.length();
for (int i = 0; i < markers.length(); i++) {
const CommentedTime &currentMarker = markers.at(i);
const GenTime &nextGenTime = markerCount - 1 == i ? m_projectDuration : markers.at(i + 1).time();
QString line(format);
QTime currentTime = QTime(0,0).addMSecs(currentMarker.time().ms());
QTime nextTime = QTime(0,0).addMSecs(nextGenTime.ms());
if (i == 0 && needCheck && currentTime.msec() != 0) {
needShowInfoMsg = true;
}
if (needCheck && currentTime.secsTo(nextTime) < 10) {
needShowInfoMsg = true;
}
line.replace("{{index}}", QString::number(i + 1));
line.replace("{{timecode}}", currentTime.hour() <= 0 ? currentTime.toString("mm:ss") : currentTime.toString("h:mm:ss"));
line.replace("{{nexttimecode}}", nextTime.hour() <= 0 ? nextTime.toString("mm:ss") : nextTime.toString("h:mm:ss"));
line.replace("{{frame}}", QString::number(currentMarker.time().frames(pCore->getCurrentFps())));
line.replace("{{comment}}", currentMarker.comment());
chapterTexts.append(line);
}
generatedContent->setPlainText(chapterTexts.join('\n'));
if (needCheck && markerCount < 3) {
needShowInfoMsg = true;
}
messageWidget->setVisible(needShowInfoMsg);
}
#undef YT_FORMAT
/*
SPDX-FileCopyrightText: 2022 Gary Wang <wzc782970009@gmail.com>
SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/
#pragma once
#include "ui_exportguidesdialog_ui.h"
#include "definitions.h"
#include "utils/timecode.h"
#include "widgets/timecodedisplay.h"
namespace Mlt {
}
/**
* @class ExportGuidesDialog
* @brief A dialog for export guides as plain text.
* @author Gary Wang
*/
class MarkerListModel;
class ExportGuidesDialog : public QDialog, public Ui::ExportGuidesDialog_UI
{
Q_OBJECT
public:
explicit ExportGuidesDialog(const MarkerListModel *model, const GenTime duration, QWidget *parent = nullptr);
~ExportGuidesDialog() override;
private:
void updateContentByModel(const QString &format, int markerIndex) const;
const MarkerListModel * m_markerListModel;
const GenTime m_projectDuration;
};
<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd">
<kpartgui name="kdenlive" version="208" translationDomain="kdenlive">
<kpartgui name="kdenlive" version="209" translationDomain="kdenlive">
<MenuBar>
<Menu name="file" >
<Action name="file_save"/>
......@@ -142,6 +142,7 @@
<Action name="edit_guide" />
<Action name="delete_guide" />
<Action name="delete_all_guides" />
<Action name="export_guides" />
<Action name="lock_guides" />
</Menu>
<Menu name="space_menu" ><text>Space</text>
......
......@@ -643,6 +643,7 @@ void MainWindow::init(const QString &mltPath)
timelineRulerMenu->addAction(actionCollection()->action(QStringLiteral("add_guide")));
timelineRulerMenu->addAction(actionCollection()->action(QStringLiteral("edit_guide")));
timelineRulerMenu->addAction(actionCollection()->action(QStringLiteral("lock_guides")));
timelineRulerMenu->addAction(actionCollection()->action(QStringLiteral("export_guides")));
timelineRulerMenu->addMenu(guideMenu);
timelineRulerMenu->addAction(actionCollection()->action(QStringLiteral("mark_in")));
timelineRulerMenu->addAction(actionCollection()->action(QStringLiteral("mark_out")));
......@@ -1816,6 +1817,7 @@ void MainWindow::setupActions()
addAction(QStringLiteral("add_guide"), i18n("Add/Remove Guide"), this, SLOT(slotAddGuide()), QIcon::fromTheme(QStringLiteral("list-add")), Qt::Key_G);
addAction(QStringLiteral("delete_guide"), i18n("Delete Guide"), this, SLOT(slotDeleteGuide()), QIcon::fromTheme(QStringLiteral("edit-delete")));
addAction(QStringLiteral("edit_guide"), i18n("Edit Guide…"), this, SLOT(slotEditGuide()), QIcon::fromTheme(QStringLiteral("document-properties")));
addAction(QStringLiteral("export_guides"), i18n("Export Guides"), this, SLOT(slotExportGuides()), QIcon::fromTheme(QStringLiteral("document-properties")));
QAction *lockGuides = addAction(QStringLiteral("lock_guides"), i18n("Guides Locked"), this, SLOT(slotLockGuides(bool)), QIcon::fromTheme(QStringLiteral("kdenlive-lock")));
lockGuides->setCheckable(true);
......@@ -2776,6 +2778,13 @@ void MainWindow::slotEditGuide()
getCurrentTimeline()->controller()->editGuide();
}
void MainWindow::slotExportGuides()
{
pCore->currentDoc()->getGuideModel()->exportGuidesGui(
this, GenTime(getMainTimeline()->controller()->duration() - 1, pCore->getCurrentFps())
);
}
void MainWindow::slotLockGuides(bool lock)
{
KdenliveSettings::setLockedGuides(lock);
......
......@@ -434,6 +434,7 @@ private slots:
void slotRemoveAllSpace();
void slotAddGuide();
void slotEditGuide();
void slotExportGuides();
void slotLockGuides(bool lock);
void slotDeleteGuide();
void slotDeleteAllGuides();
......
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ExportGuidesDialog_UI</class>
<widget class="QDialog" name="ExportGuidesDialog_UI">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>529</width>
<height>390</height>
</rect>
</property>
<property name="windowTitle">
<string>Marker</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="4" column="1">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Close</set>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QPlainTextEdit" name="generatedContent">
<property name="readOnly">
<bool>true</bool>
</property>
<property name="placeholderText">
<string>Formatted chapter marker text will be generated here.</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="formatEdit"/>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="markerTypeComboBox">
<property name="editable">
<bool>false</bool>
</property>
<property name="currentText">
<string>Any</string>
</property>
<property name="currentIndex">
<number>0</number>
</property>
<item>
<property name="text">
<string>Any</string>
</property>
<property name="icon">
<iconset theme="edit-select-all">
<normaloff>.</normaloff>.</iconset>
</property>
</item>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Marker Type:</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Format:</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Exported:</string>
</property>
</widget>
</item>
<item row="3" column="0" colspan="2">
<widget class="KMessageWidget" name="messageWidget">
<property name="closeButtonVisible" stdset="0">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>ExportGuidesDialog_UI</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>ExportGuidesDialog_UI</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment