File indexing completed on 2022-11-22 14:07:13

0001 /*
0002     SPDX-FileCopyrightText: 2008 Jean-Baptiste Mardelle <jb@kdenlive.org>
0003 
0004 SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0005 */
0006 
0007 #pragma once
0008 
0009 #include <QPainter>
0010 #include <QPushButton>
0011 #include <QStyledItemDelegate>
0012 
0013 #ifdef KF5_USE_PURPOSE
0014 namespace Purpose {
0015 class Menu;
0016 }
0017 #endif
0018 
0019 #include "bin/model/markerlistmodel.hpp"
0020 #include "definitions.h"
0021 #include "renderpresets/tree/renderpresettreemodel.hpp"
0022 #include "ui_renderwidget_ui.h"
0023 #include <knewstuff_version.h>
0024 #include <KNSWidgets/Button>
0025 
0026 class QDomElement;
0027 class QKeyEvent;
0028 
0029 // RenderViewDelegate is used to draw the progress bars.
0030 class RenderViewDelegate : public QStyledItemDelegate
0031 {
0032     Q_OBJECT
0033 public:
0034     explicit RenderViewDelegate(QWidget *parent)
0035         : QStyledItemDelegate(parent)
0036     {
0037     }
0038 
0039     void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override
0040     {
0041         if (index.column() == 1) {
0042             painter->save();
0043             QStyleOptionViewItem opt(option);
0044             QStyle *style = opt.widget ? opt.widget->style() : QApplication::style();
0045             const int textMargin = style->pixelMetric(QStyle::PM_FocusFrameHMargin) + 1;
0046             style->drawPrimitive(QStyle::PE_PanelItemViewItem, &opt, painter, opt.widget);
0047 
0048             QFont font = painter->font();
0049             font.setBold(true);
0050             painter->setFont(font);
0051             QRect r1 = option.rect;
0052             r1.adjust(0, textMargin, 0, -textMargin);
0053             int mid = int((r1.height() / 2));
0054             r1.setBottom(r1.y() + mid);
0055             QRect bounding;
0056             painter->drawText(r1, Qt::AlignLeft | Qt::AlignTop, index.data().toString(), &bounding);
0057             r1.moveTop(r1.bottom() - textMargin);
0058             font.setBold(false);
0059             painter->setFont(font);
0060             painter->drawText(r1, Qt::AlignLeft | Qt::AlignTop, index.data(Qt::UserRole).toString());
0061             int progress = index.data(Qt::UserRole + 3).toInt();
0062             if (progress > 0 && progress < 100) {
0063                 // draw progress bar
0064                 QColor color = option.palette.alternateBase().color();
0065                 QColor fgColor = option.palette.text().color();
0066                 color.setAlpha(150);
0067                 fgColor.setAlpha(150);
0068                 painter->setBrush(QBrush(color));
0069                 painter->setPen(QPen(fgColor));
0070                 int width = qMin(200, r1.width() - 4);
0071                 QRect bgrect(r1.left() + 2, option.rect.bottom() - 6 - textMargin, width, 6);
0072                 painter->drawRoundedRect(bgrect, 3, 3);
0073                 painter->setBrush(QBrush(fgColor));
0074                 bgrect.adjust(2, 2, 0, -1);
0075                 painter->setPen(Qt::NoPen);
0076                 bgrect.setWidth((width - 2) * progress / 100);
0077                 painter->drawRect(bgrect);
0078             } else {
0079                 r1.setBottom(opt.rect.bottom());
0080                 r1.setTop(r1.bottom() - mid);
0081                 painter->drawText(r1, Qt::AlignLeft | Qt::AlignBottom, index.data(Qt::UserRole + 5).toString());
0082             }
0083             painter->restore();
0084         } else {
0085             QStyledItemDelegate::paint(painter, option, index);
0086         }
0087     }
0088 };
0089 
0090 class RenderJobItem : public QTreeWidgetItem
0091 {
0092 public:
0093     explicit RenderJobItem(QTreeWidget *parent, const QStringList &strings, int type = QTreeWidgetItem::Type);
0094     void setStatus(int status);
0095     int status() const;
0096     void setMetadata(const QString &data);
0097     const QString metadata() const;
0098 
0099 private:
0100     int m_status;
0101     QString m_data;
0102 };
0103 
0104 class RenderWidget : public QDialog
0105 {
0106     Q_OBJECT
0107 
0108 public:
0109     enum RenderError {
0110         CompositeError = 0,
0111         PresetError = 1,
0112         ProxyWarning = 2,
0113         PlaybackError = 3,
0114         OptionsError = 4
0115     };
0116 
0117     explicit RenderWidget(bool enableProxy, QWidget *parent = nullptr);
0118     ~RenderWidget() override;
0119     void saveConfig();
0120     void loadConfig();
0121     void setGuides(std::weak_ptr<MarkerListModel> guidesModel);
0122     void focusItem(const QString &profile = QString());
0123     void setRenderProgress(const QString &dest, int progress = 0, int frame = 0);
0124     void setRenderStatus(const QString &dest, int status, const QString &error);
0125     void setRenderProfile(const QMap<QString, QString> &props);
0126     void saveRenderProfile();
0127     void updateDocumentPath();
0128     int waitingJobsCount() const;
0129     int runningJobsCount() const;
0130     QString getFreeScriptName(const QUrl &projectName = QUrl(), const QString &prefix = QString());
0131     bool startWaitingRenderJobs();
0132     /** @brief Show / hide proxy settings. */
0133     void updateProxyConfig(bool enable);
0134 
0135     /** @brief Display warning message in render widget. */
0136     void errorMessage(RenderError type, const QString &message);
0137 
0138 protected:
0139     QSize sizeHint() const override;
0140     void keyPressEvent(QKeyEvent *e) override;
0141     void parseProfile(QDomElement profile, QTreeWidgetItem *childitem, QString groupName,
0142                       QString extension = QString(), QString renderer = QStringLiteral("avformat"));
0143 
0144 public slots:
0145     void slotAbortCurrentJob();
0146     void slotPrepareExport(bool scriptExport = false, const QString &scriptPath = QString());
0147     void adjustViewToProfile();
0148     void reloadGuides();
0149     /** @brief Adjust render file name to current project name. */
0150     void resetRenderPath(const QString &path);
0151     /** @brief Update metadata tooltip with current values. */
0152     void updateMetadataToolTip();
0153 
0154 private slots:
0155     /**
0156      * Will be called when the user selects an output file via the file dialog.
0157      * File extension will be added automatically.
0158      */
0159     void slotUpdateButtons(const QUrl &url);
0160     /**
0161      * Will be called when the user changes the output file path in the text line.
0162      * File extension must NOT be added, would make editing impossible!
0163      */
0164     void slotUpdateButtons();
0165     void refreshView();
0166 
0167     void slotChangeSelection(const QModelIndex &current, const QModelIndex &previous);
0168     /** @brief Updates available options when a new format has been selected. */
0169     void loadProfile();
0170     void refreshParams();
0171     void slotSavePresetAs();
0172     void slotNewPreset();
0173     void slotEditPreset();
0174 
0175     void slotRenderModeChanged();
0176     void slotUpdateRescaleHeight(int);
0177     void slotUpdateRescaleWidth(int);
0178     void slotSwitchAspectRatio();
0179     void slotCheckStartGuidePosition();
0180     void slotCheckEndGuidePosition();
0181     /** @brief Enable / disable the rescale options. */
0182     void setRescaleEnabled(bool enable);
0183     /** @brief Show updated command parameter in tooltip. */
0184     void adjustSpeed(int videoQuality);
0185 
0186     void slotStartScript();
0187     void slotDeleteScript();
0188     void parseScriptFiles();
0189     void slotCheckScript();
0190     void slotCheckJob();
0191     void slotCleanUpJobs();
0192 
0193     void slotHideLog();
0194     void slotPlayRendering(QTreeWidgetItem *item, int);
0195     void slotStartCurrentJob();
0196     /** @brief User shared a rendered file, give feedback. */
0197     void slotShareActionFinished(const QJsonObject &output, int error, const QString &message);
0198     /** @brief running jobs menu. */
0199     void prepareJobContextMenu(const QPoint &pos);
0200 
0201 private:
0202     enum Tabs {
0203         RenderTab = 0,
0204         JobsTab,
0205         ScriptsTab
0206     };
0207 
0208     Ui::RenderWidget_UI m_view;
0209     QString m_projectFolder;
0210     RenderViewDelegate *m_scriptsDelegate;
0211     RenderViewDelegate *m_jobsDelegate;
0212     bool m_blockProcessing;
0213     QString m_renderer;
0214     QMap<int, QString> m_errorMessages;
0215     std::weak_ptr<MarkerListModel> m_guidesModel;
0216 
0217     std::shared_ptr<RenderPresetTreeModel> m_treeModel;
0218     QString m_currentProfile;
0219 
0220 #ifdef KF5_USE_PURPOSE
0221     Purpose::Menu *m_shareMenu;
0222 #endif
0223     void parseProfiles(const QString &selectedProfile = QString());
0224     QUrl filenameWithExtension(QUrl url, const QString &extension);
0225     /** @brief Check if a job needs to be started. */
0226     void checkRenderStatus();
0227     void startRendering(RenderJobItem *item);
0228     /** @brief Create a rendering profile from MLT preset. */
0229     QTreeWidgetItem *loadFromMltPreset(const QString &groupName, const QString &path, QString profileName, bool codecInName = false);
0230     void prepareRendering(bool delayedRendering);
0231     /** @brief Create a new empty playlist (*.mlt) file and @returns the filename of the created file */
0232     QString generatePlaylistFile(bool delayedRendering);
0233     void generateRenderFiles(QDomDocument doc, int in, int out, QString outputFile, bool delayedRendering, const QString &subtitleFile = QString());
0234     RenderJobItem *createRenderJob(const QString &playlist, const QString &outputFile, int in, int out, const QString &subtitleFile = QString());
0235 
0236 signals:
0237     void abortProcess(const QString &url);
0238     /** Send the info about rendering that will be saved in the document:
0239     (profile destination, profile name and url of rendered file) */
0240     void selectedRenderProfile(const QMap<QString, QString> &renderProps);
0241     void shutdown();
0242 };