From 0e2fe1059565daaa6cdc70912004cd43c06f3ca4 Mon Sep 17 00:00:00 2001 From: Anthony Torres Date: Fri, 12 Apr 2019 17:38:17 -0400 Subject: [PATCH 1/2] UI: Separate delegate class into header file --- UI/window-remux.cpp | 352 +++++++++++++++++++++----------------------- UI/window-remux.hpp | 30 ++++ 2 files changed, 201 insertions(+), 181 deletions(-) diff --git a/UI/window-remux.cpp b/UI/window-remux.cpp index 03e1ca369..c8f15ce90 100644 --- a/UI/window-remux.cpp +++ b/UI/window-remux.cpp @@ -57,216 +57,206 @@ enum RemuxEntryRole { Delegate - Presents cells in the grid. **********************************************************/ -class RemuxEntryPathItemDelegate : public QStyledItemDelegate { -public: +RemuxEntryPathItemDelegate::RemuxEntryPathItemDelegate(bool isOutput, + const QString &defaultPath) + : QStyledItemDelegate(), + isOutput(isOutput), + defaultPath(defaultPath) +{ +} - RemuxEntryPathItemDelegate(bool isOutput, const QString &defaultPath) - : QStyledItemDelegate(), - isOutput(isOutput), - defaultPath(defaultPath) - { - } +QWidget *RemuxEntryPathItemDelegate::createEditor(QWidget *parent, + const QStyleOptionViewItem & /* option */, + const QModelIndex &index) const +{ + RemuxEntryState state = index.model() + ->index(index.row(), RemuxEntryColumn::State) + .data(RemuxEntryRole::EntryStateRole) + .value(); + if (state == RemuxEntryState::Pending || + state == RemuxEntryState::InProgress) { + // Never allow modification of rows that are + // in progress. + return Q_NULLPTR; + } else if (isOutput && state != RemuxEntryState::Ready) { + // Do not allow modification of output rows + // that aren't associated with a valid input. + return Q_NULLPTR; + } else if (!isOutput && state == RemuxEntryState::Complete) { + // Don't allow modification of rows that are + // already complete. + return Q_NULLPTR; + } else { + QSizePolicy buttonSizePolicy( + QSizePolicy::Policy::Minimum, + QSizePolicy::Policy::Expanding, + QSizePolicy::ControlType::PushButton); - virtual QWidget *createEditor(QWidget *parent, - const QStyleOptionViewItem & /* option */, - const QModelIndex &index) const override - { - RemuxEntryState state = index.model() - ->index(index.row(), RemuxEntryColumn::State) - .data(RemuxEntryRole::EntryStateRole) - .value(); - if (state == RemuxEntryState::Pending || - state == RemuxEntryState::InProgress) { - // Never allow modification of rows that are - // in progress. - return Q_NULLPTR; - } else if (isOutput && state != RemuxEntryState::Ready) { - // Do not allow modification of output rows - // that aren't associated with a valid input. - return Q_NULLPTR; - } else if (!isOutput && state == RemuxEntryState::Complete) { - // Don't allow modification of rows that are - // already complete. - return Q_NULLPTR; - } else { - QSizePolicy buttonSizePolicy( - QSizePolicy::Policy::Minimum, - QSizePolicy::Policy::Expanding, - QSizePolicy::ControlType::PushButton); + QWidget *container = new QWidget(parent); - QWidget *container = new QWidget(parent); + auto browseCallback = [this, container]() + { + const_cast(this) + ->handleBrowse(container); + }; - auto browseCallback = [this, container]() - { - const_cast(this) - ->handleBrowse(container); - }; + auto clearCallback = [this, container]() + { + const_cast(this) + ->handleClear(container); + }; - auto clearCallback = [this, container]() - { - const_cast(this) - ->handleClear(container); - }; + QHBoxLayout *layout = new QHBoxLayout(); + layout->setMargin(0); + layout->setSpacing(0); - QHBoxLayout *layout = new QHBoxLayout(); - layout->setMargin(0); - layout->setSpacing(0); + QLineEdit *text = new QLineEdit(); + text->setObjectName(QStringLiteral("text")); + text->setSizePolicy(QSizePolicy( + QSizePolicy::Policy::Expanding, + QSizePolicy::Policy::Expanding, + QSizePolicy::ControlType::LineEdit)); + layout->addWidget(text); - QLineEdit *text = new QLineEdit(); - text->setObjectName(QStringLiteral("text")); - text->setSizePolicy(QSizePolicy( - QSizePolicy::Policy::Expanding, - QSizePolicy::Policy::Expanding, - QSizePolicy::ControlType::LineEdit)); - layout->addWidget(text); + QToolButton *browseButton = new QToolButton(); + browseButton->setText("..."); + browseButton->setSizePolicy(buttonSizePolicy); + layout->addWidget(browseButton); - QToolButton *browseButton = new QToolButton(); - browseButton->setText("..."); - browseButton->setSizePolicy(buttonSizePolicy); - layout->addWidget(browseButton); + container->connect(browseButton, &QToolButton::clicked, + browseCallback); - container->connect(browseButton, &QToolButton::clicked, - browseCallback); + // The "clear" button is not shown in output cells + // or the insertion point's input cell. + if (!isOutput && state != RemuxEntryState::Empty) { + QToolButton *clearButton = new QToolButton(); + clearButton->setText("X"); + clearButton->setSizePolicy(buttonSizePolicy); + layout->addWidget(clearButton); - // The "clear" button is not shown in output cells - // or the insertion point's input cell. - if (!isOutput && state != RemuxEntryState::Empty) { - QToolButton *clearButton = new QToolButton(); - clearButton->setText("X"); - clearButton->setSizePolicy(buttonSizePolicy); - layout->addWidget(clearButton); - - container->connect(clearButton, - &QToolButton::clicked, - clearCallback); - } - - container->setLayout(layout); - container->setFocusProxy(text); - - return container; + container->connect(clearButton, + &QToolButton::clicked, + clearCallback); } + + container->setLayout(layout); + container->setFocusProxy(text); + return container; } +} - virtual void setEditorData(QWidget *editor, const QModelIndex &index) - const override - { - QLineEdit *text = editor->findChild(); - text->setText(index.data().toString()); - - editor->setProperty(PATH_LIST_PROP, QVariant()); - } - - virtual void setModelData(QWidget *editor, - QAbstractItemModel *model, - const QModelIndex &index) const override - { - // We use the PATH_LIST_PROP property to pass a list of - // path strings from the editor widget into the model's - // NewPathsToProcessRole. This is only used when paths - // are selected through the "browse" or "delete" buttons - // in the editor. If the user enters new text in the - // text box, we simply pass that text on to the model - // as normal text data in the default role. - QVariant pathListProp = editor->property(PATH_LIST_PROP); - if (pathListProp.isValid()) { - QStringList list = editor->property(PATH_LIST_PROP) - .toStringList(); - if (isOutput) { - if (list.size() > 0) - model->setData(index, list); - } else - model->setData(index, list, - RemuxEntryRole::NewPathsToProcessRole); - } else { - QLineEdit *lineEdit = editor->findChild(); - model->setData(index, lineEdit->text()); - } - } - - virtual void paint(QPainter *painter, - const QStyleOptionViewItem &option, - const QModelIndex &index) const override - { - RemuxEntryState state = index.model() - ->index(index.row(), RemuxEntryColumn::State) - .data(RemuxEntryRole::EntryStateRole) - .value(); - - QStyleOptionViewItem localOption = option; - initStyleOption(&localOption, index); +void RemuxEntryPathItemDelegate::setEditorData(QWidget *editor, + const QModelIndex &index) const +{ + QLineEdit *text = editor->findChild(); + text->setText(index.data().toString()); + editor->setProperty(PATH_LIST_PROP, QVariant()); +} +void RemuxEntryPathItemDelegate::setModelData(QWidget *editor, + QAbstractItemModel *model, + const QModelIndex &index) const +{ + // We use the PATH_LIST_PROP property to pass a list of + // path strings from the editor widget into the model's + // NewPathsToProcessRole. This is only used when paths + // are selected through the "browse" or "delete" buttons + // in the editor. If the user enters new text in the + // text box, we simply pass that text on to the model + // as normal text data in the default role. + QVariant pathListProp = editor->property(PATH_LIST_PROP); + if (pathListProp.isValid()) { + QStringList list = editor->property(PATH_LIST_PROP) + .toStringList(); if (isOutput) { - if (state != Ready) { - QColor background = localOption.palette - .color(QPalette::ColorGroup::Disabled, - QPalette::ColorRole::Background); + if (list.size() > 0) + model->setData(index, list); + } else + model->setData(index, list, + RemuxEntryRole::NewPathsToProcessRole); + } else { + QLineEdit *lineEdit = editor->findChild(); + model->setData(index, lineEdit->text()); + } +} - localOption.backgroundBrush = QBrush(background); - } +void RemuxEntryPathItemDelegate::paint(QPainter *painter, + const QStyleOptionViewItem &option, + const QModelIndex &index) const +{ + RemuxEntryState state = index.model() + ->index(index.row(), RemuxEntryColumn::State) + .data(RemuxEntryRole::EntryStateRole) + .value(); + + QStyleOptionViewItem localOption = option; + initStyleOption(&localOption, index); + + if (isOutput) { + if (state != Ready) { + QColor background = localOption.palette + .color(QPalette::ColorGroup::Disabled, + QPalette::ColorRole::Background); + + localOption.backgroundBrush = QBrush(background); } - - QApplication::style()->drawControl(QStyle::CE_ItemViewItem, - &localOption, painter); } -private: - bool isOutput; - QString defaultPath; + QApplication::style()->drawControl(QStyle::CE_ItemViewItem, + &localOption, painter); +} - const char *PATH_LIST_PROP = "pathList"; +void RemuxEntryPathItemDelegate::handleBrowse(QWidget *container) +{ + QString OutputPattern = + "(*.mp4 *.flv *.mov *.mkv *.ts *.m3u8)"; + QString InputPattern = + "(*.flv *.mov *.mkv *.ts *.m3u8)"; - void handleBrowse(QWidget *container) - { - QString OutputPattern = - "(*.mp4 *.flv *.mov *.mkv *.ts *.m3u8)"; - QString InputPattern = - "(*.flv *.mov *.mkv *.ts *.m3u8)"; + QLineEdit *text = container->findChild(); - QLineEdit *text = container->findChild(); + QString currentPath = text->text(); + if (currentPath.isEmpty()) + currentPath = defaultPath; - QString currentPath = text->text(); - if (currentPath.isEmpty()) - currentPath = defaultPath; + bool isSet = false; + if (isOutput) { + QString newPath = QFileDialog::getSaveFileName( + container, QTStr("Remux.SelectTarget"), + currentPath, OutputPattern); - bool isSet = false; - if (isOutput) { - QString newPath = QFileDialog::getSaveFileName( - container, QTStr("Remux.SelectTarget"), - currentPath, OutputPattern); - - if (!newPath.isEmpty()) { - container->setProperty(PATH_LIST_PROP, - QStringList() << newPath); - isSet = true; - } - } else { - QStringList paths = QFileDialog::getOpenFileNames( - container, - QTStr("Remux.SelectRecording"), - currentPath, - QTStr("Remux.OBSRecording") - + QString(" ") + InputPattern); - - if (!paths.empty()) { - container->setProperty(PATH_LIST_PROP, paths); - isSet = true; - } + if (!newPath.isEmpty()) { + container->setProperty(PATH_LIST_PROP, + QStringList() << newPath); + isSet = true; } + } else { + QStringList paths = QFileDialog::getOpenFileNames( + container, + QTStr("Remux.SelectRecording"), + currentPath, + QTStr("Remux.OBSRecording") + + QString(" ") + InputPattern); - if (isSet) - emit commitData(container); + if (!paths.empty()) { + container->setProperty(PATH_LIST_PROP, paths); + isSet = true; + } } - void handleClear(QWidget *container) - { - // An empty string list will indicate that the entry is being - // blanked and should be deleted. - container->setProperty(PATH_LIST_PROP, QStringList()); - + if (isSet) emit commitData(container); - } -}; +} + +void RemuxEntryPathItemDelegate::handleClear(QWidget *container) +{ + // An empty string list will indicate that the entry is being + // blanked and should be deleted. + container->setProperty(PATH_LIST_PROP, QStringList()); + + emit commitData(container); +} + /********************************************************** Model - Manages the queue's data diff --git a/UI/window-remux.hpp b/UI/window-remux.hpp index ce5b168c3..ad78fb756 100644 --- a/UI/window-remux.hpp +++ b/UI/window-remux.hpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include "ui_OBSRemux.h" @@ -160,3 +161,32 @@ signals: friend class OBSRemux; }; + +class RemuxEntryPathItemDelegate : public QStyledItemDelegate { + Q_OBJECT + +public: + RemuxEntryPathItemDelegate(bool isOutput, const QString &defaultPath); + + virtual QWidget *createEditor(QWidget *parent, + const QStyleOptionViewItem & /* option */, + const QModelIndex &index) const override; + + virtual void setEditorData(QWidget *editor, const QModelIndex &index) + const override; + virtual void setModelData(QWidget *editor, + QAbstractItemModel *model, + const QModelIndex &index) const override; + virtual void paint(QPainter *painter, + const QStyleOptionViewItem &option, + const QModelIndex &index) const override; + +private: + bool isOutput; + QString defaultPath; + const char *PATH_LIST_PROP = "pathList"; + + void handleBrowse(QWidget *container); + void handleClear(QWidget *container); + +}; From 7ddab80d8005b142b61ef79b29b0ab1b877c8142 Mon Sep 17 00:00:00 2001 From: Anthony Torres Date: Fri, 12 Apr 2019 17:39:10 -0400 Subject: [PATCH 2/2] UI: Fix remux dialog ignoring filename changes --- UI/window-remux.cpp | 6 ++++++ UI/window-remux.hpp | 2 ++ 2 files changed, 8 insertions(+) diff --git a/UI/window-remux.cpp b/UI/window-remux.cpp index c8f15ce90..f6fa08b94 100644 --- a/UI/window-remux.cpp +++ b/UI/window-remux.cpp @@ -150,6 +150,7 @@ void RemuxEntryPathItemDelegate::setEditorData(QWidget *editor, { QLineEdit *text = editor->findChild(); text->setText(index.data().toString()); + QObject::connect(text, SIGNAL(textEdited(QString)), this, SLOT(updateText())); editor->setProperty(PATH_LIST_PROP, QVariant()); } @@ -257,6 +258,11 @@ void RemuxEntryPathItemDelegate::handleClear(QWidget *container) emit commitData(container); } +void RemuxEntryPathItemDelegate::updateText() { + QLineEdit *lineEdit = dynamic_cast(sender()); + QWidget *editor = lineEdit->parentWidget(); + emit commitData(editor); +} /********************************************************** Model - Manages the queue's data diff --git a/UI/window-remux.hpp b/UI/window-remux.hpp index ad78fb756..c98d45abe 100644 --- a/UI/window-remux.hpp +++ b/UI/window-remux.hpp @@ -189,4 +189,6 @@ private: void handleBrowse(QWidget *container); void handleClear(QWidget *container); +private slots: + void updateText(); };