From ddca6a5e01f6bc8ea8e1780f02989a2472d75035 Mon Sep 17 00:00:00 2001 From: Mike Solar Date: Thu, 16 Jul 2026 22:53:13 +0800 Subject: [PATCH] proxy: add dedicated Proxy dialog and preferences fields - New ProxyDialog (Tools > Proxy Settings..., plus 'Proxy Settings...' in the project panel and timeline Proxy submenus) unifying global proxy settings, per-footage custom presets, generation and deletion in one place instead of three scattered entry points; this also fixes the Tools menu action opening the wrong preferences tab - Preferences Disk tab gains an 'include audio in proxies' checkbox and an ffmpeg executable path field (blank = auto-detect) - Add ProxyDialog smoke tests --- app/dialog/CMakeLists.txt | 1 + .../preferences/tabs/preferencesdisktab.cpp | 30 ++ .../preferences/tabs/preferencesdisktab.h | 2 + app/dialog/proxy/CMakeLists.txt | 22 ++ app/dialog/proxy/proxydialog.cpp | 330 ++++++++++++++++++ app/dialog/proxy/proxydialog.h | 101 ++++++ .../projectexplorer/projectexplorer.cpp | 12 + app/widget/projectexplorer/projectexplorer.h | 2 + app/widget/timelinewidget/timelinewidget.cpp | 12 + app/widget/timelinewidget/timelinewidget.h | 2 + app/window/mainwindow/mainmenu.cpp | 7 +- tests/gtest/CMakeLists.txt | 1 + tests/gtest/proxy_dialog_test.cpp | 72 ++++ 13 files changed, 592 insertions(+), 2 deletions(-) create mode 100644 app/dialog/proxy/CMakeLists.txt create mode 100644 app/dialog/proxy/proxydialog.cpp create mode 100644 app/dialog/proxy/proxydialog.h create mode 100644 tests/gtest/proxy_dialog_test.cpp diff --git a/app/dialog/CMakeLists.txt b/app/dialog/CMakeLists.txt index adaf11b49..b4990d624 100644 --- a/app/dialog/CMakeLists.txt +++ b/app/dialog/CMakeLists.txt @@ -30,6 +30,7 @@ if (OpenTimelineIO_FOUND) endif () add_subdirectory(preferences) add_subdirectory(progress) +add_subdirectory(proxy) add_subdirectory(projectproperties) add_subdirectory(rendercancel) add_subdirectory(sequence) diff --git a/app/dialog/preferences/tabs/preferencesdisktab.cpp b/app/dialog/preferences/tabs/preferencesdisktab.cpp index e6d71a612..0f2d6a9c7 100644 --- a/app/dialog/preferences/tabs/preferencesdisktab.cpp +++ b/app/dialog/preferences/tabs/preferencesdisktab.cpp @@ -139,6 +139,33 @@ PreferencesDiskTab::PreferencesDiskTab() proxy_preset_combo_->setCurrentText(OLIVE_CONFIG("ProxyPreset").toString()); proxy_layout->addWidget(proxy_preset_combo_, proxy_row, 3); + proxy_row++; + + proxy_include_audio_checkbox_ = + new QCheckBox(tr("Include audio in proxies")); + proxy_include_audio_checkbox_->setChecked( + OLIVE_CONFIG("ProxyIncludeAudio").toBool()); + proxy_layout->addWidget(proxy_include_audio_checkbox_, proxy_row, 0, 1, 2); + + proxy_row++; + + proxy_layout->addWidget(new QLabel(tr("ffmpeg Executable:")), proxy_row, + 0); + proxy_ffmpeg_path_edit_ = + new QLineEdit(OLIVE_CONFIG("FFmpegPath").toString()); + proxy_ffmpeg_path_edit_->setPlaceholderText(tr("Auto-detect")); + proxy_layout->addWidget(proxy_ffmpeg_path_edit_, proxy_row, 1); + + QPushButton *ffmpeg_browse_btn = new QPushButton(tr("Browse...")); + connect(ffmpeg_browse_btn, &QPushButton::clicked, this, [this]() { + const QString file = QFileDialog::getOpenFileName( + this, tr("Select ffmpeg Executable")); + if (!file.isEmpty()) { + proxy_ffmpeg_path_edit_->setText(file); + } + }); + proxy_layout->addWidget(ffmpeg_browse_btn, proxy_row, 2); + outer_layout->addStretch(); } @@ -183,6 +210,9 @@ void PreferencesDiskTab::Accept(MultiUndoCommand *command) static_cast(proxy_height_slider_->GetValue()); OLIVE_CONFIG("ProxyCRF") = static_cast(proxy_crf_slider_->GetValue()); OLIVE_CONFIG("ProxyPreset") = proxy_preset_combo_->currentText(); + OLIVE_CONFIG("ProxyIncludeAudio") = + proxy_include_audio_checkbox_->isChecked(); + OLIVE_CONFIG("FFmpegPath") = proxy_ffmpeg_path_edit_->text().trimmed(); } } diff --git a/app/dialog/preferences/tabs/preferencesdisktab.h b/app/dialog/preferences/tabs/preferencesdisktab.h index ee2a4767a..a707f1adb 100644 --- a/app/dialog/preferences/tabs/preferencesdisktab.h +++ b/app/dialog/preferences/tabs/preferencesdisktab.h @@ -58,6 +58,8 @@ private: IntegerSlider *proxy_height_slider_; IntegerSlider *proxy_crf_slider_; QComboBox *proxy_preset_combo_; + QCheckBox *proxy_include_audio_checkbox_; + QLineEdit *proxy_ffmpeg_path_edit_; }; } diff --git a/app/dialog/proxy/CMakeLists.txt b/app/dialog/proxy/CMakeLists.txt new file mode 100644 index 000000000..f7ca71f87 --- /dev/null +++ b/app/dialog/proxy/CMakeLists.txt @@ -0,0 +1,22 @@ +# Oak Video Editor - Non-Linear Video Editor +# Copyright (C) 2026 Oak Team +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +set(OLIVE_SOURCES + ${OLIVE_SOURCES} + dialog/proxy/proxydialog.cpp + dialog/proxy/proxydialog.h + PARENT_SCOPE +) diff --git a/app/dialog/proxy/proxydialog.cpp b/app/dialog/proxy/proxydialog.cpp new file mode 100644 index 000000000..619651725 --- /dev/null +++ b/app/dialog/proxy/proxydialog.cpp @@ -0,0 +1,330 @@ +/* + * Oak Video Editor - Non-Linear Video Editor + * Copyright (C) 2026 Oak Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "proxydialog.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "config/config.h" +#include "node/project.h" + +namespace olive +{ + +ProxyDialog::ProxyDialog(QWidget *parent, const QVector &footage) + : QDialog(parent) + , footage_(footage) + , footage_tree_(nullptr) + , custom_params_checkbox_(nullptr) +{ + setWindowTitle(tr("Proxy Settings")); + + const ProxyManager::ProxyParams params = + ProxyManager::ProxyParamsFromConfig(); + + QVBoxLayout *layout = new QVBoxLayout(this); + + if (!footage_.isEmpty()) { + QGroupBox *footage_group = new QGroupBox(tr("Selected Footage")); + layout->addWidget(footage_group); + QVBoxLayout *footage_layout = new QVBoxLayout(footage_group); + + footage_tree_ = new QTreeWidget(); + footage_tree_->setHeaderLabels({ tr("Footage"), tr("Proxy State") }); + footage_tree_->setRootIsDecorated(false); + footage_layout->addWidget(footage_tree_); + RefreshFootageList(); + + custom_params_checkbox_ = + new QCheckBox(tr("Use custom settings for selected footage")); + bool any_custom = false; + for (const Footage *item : footage_) { + if (item->has_custom_proxy_params()) { + any_custom = true; + break; + } + } + custom_params_checkbox_->setChecked(any_custom); + footage_layout->addWidget(custom_params_checkbox_); + } + + QGroupBox *settings_group = new QGroupBox(tr("Global Proxy Settings")); + layout->addWidget(settings_group); + QGridLayout *settings_layout = new QGridLayout(settings_group); + + int row = 0; + + settings_layout->addWidget(new QLabel(tr("Proxy Width:")), row, 0); + width_slider_ = new IntegerSlider(); + width_slider_->SetMinimum(160); + width_slider_->SetMaximum(4096); + width_slider_->SetValue(params.width); + settings_layout->addWidget(width_slider_, row, 1); + + settings_layout->addWidget(new QLabel(tr("Proxy Height:")), row, 2); + height_slider_ = new IntegerSlider(); + height_slider_->SetMinimum(120); + height_slider_->SetMaximum(2160); + height_slider_->SetValue(params.height); + settings_layout->addWidget(height_slider_, row, 3); + + row++; + + settings_layout->addWidget(new QLabel(tr("Proxy CRF:")), row, 0); + crf_slider_ = new IntegerSlider(); + crf_slider_->SetMinimum(0); + crf_slider_->SetMaximum(51); + crf_slider_->SetValue(params.crf); + settings_layout->addWidget(crf_slider_, row, 1); + + settings_layout->addWidget(new QLabel(tr("Proxy Preset:")), row, 2); + preset_combo_ = new QComboBox(); + const QStringList presets = { + QStringLiteral("ultrafast"), QStringLiteral("superfast"), + QStringLiteral("veryfast"), QStringLiteral("faster"), + QStringLiteral("fast"), QStringLiteral("medium"), + QStringLiteral("slow"), QStringLiteral("slower"), + QStringLiteral("veryslow"), + }; + for (const QString &preset : presets) { + preset_combo_->addItem(preset); + } + preset_combo_->setCurrentText(params.preset); + settings_layout->addWidget(preset_combo_, row, 3); + + row++; + + include_audio_checkbox_ = new QCheckBox(tr("Include audio in proxies")); + include_audio_checkbox_->setChecked(params.include_audio); + settings_layout->addWidget(include_audio_checkbox_, row, 0, 1, 2); + + row++; + + settings_layout->addWidget(new QLabel(tr("ffmpeg Executable:")), row, 0); + ffmpeg_path_edit_ = new QLineEdit(OLIVE_CONFIG("FFmpegPath").toString()); + ffmpeg_path_edit_->setPlaceholderText(tr("Auto-detect")); + settings_layout->addWidget(ffmpeg_path_edit_, row, 1); + + QPushButton *ffmpeg_browse_btn = new QPushButton(tr("Browse...")); + connect(ffmpeg_browse_btn, &QPushButton::clicked, this, + &ProxyDialog::BrowseForFFmpeg); + settings_layout->addWidget(ffmpeg_browse_btn, row, 2); + + QHBoxLayout *button_layout = new QHBoxLayout(); + layout->addLayout(button_layout); + + if (!footage_.isEmpty()) { + QPushButton *generate_btn = new QPushButton(tr("Generate Proxies")); + connect(generate_btn, &QPushButton::clicked, this, + &ProxyDialog::GenerateProxies); + button_layout->addWidget(generate_btn); + + QPushButton *delete_btn = new QPushButton(tr("Delete Proxies")); + connect(delete_btn, &QPushButton::clicked, this, + &ProxyDialog::DeleteProxies); + button_layout->addWidget(delete_btn); + } + + button_layout->addStretch(); + + QPushButton *close_btn = new QPushButton(tr("Close")); + connect(close_btn, &QPushButton::clicked, this, &ProxyDialog::accept); + button_layout->addWidget(close_btn); +} + +void ProxyDialog::accept() +{ + SaveGlobalSettings(); + + if (!footage_.isEmpty()) { + for (Footage *item : footage_) { + if (custom_params_checkbox_->isChecked()) { + item->SetCustomProxyParams(CurrentParams()); + } else { + item->ClearCustomProxyParams(); + } + } + } + + QDialog::accept(); +} + +int ProxyDialog::ProxyWidth() const +{ + return static_cast(width_slider_->GetValue()); +} + +int ProxyDialog::ProxyHeight() const +{ + return static_cast(height_slider_->GetValue()); +} + +int ProxyDialog::ProxyCRF() const +{ + return static_cast(crf_slider_->GetValue()); +} + +QString ProxyDialog::ProxyPreset() const +{ + return preset_combo_->currentText(); +} + +bool ProxyDialog::ProxyIncludeAudio() const +{ + return include_audio_checkbox_->isChecked(); +} + +QString ProxyDialog::FFmpegPath() const +{ + return ffmpeg_path_edit_->text(); +} + +void ProxyDialog::SetProxyWidth(int width) +{ + width_slider_->SetValue(width); +} + +void ProxyDialog::SetProxyHeight(int height) +{ + height_slider_->SetValue(height); +} + +void ProxyDialog::SetProxyCRF(int crf) +{ + crf_slider_->SetValue(crf); +} + +void ProxyDialog::SetProxyPreset(const QString &preset) +{ + preset_combo_->setCurrentText(preset); +} + +void ProxyDialog::SetProxyIncludeAudio(bool include_audio) +{ + include_audio_checkbox_->setChecked(include_audio); +} + +void ProxyDialog::SetFFmpegPath(const QString &path) +{ + ffmpeg_path_edit_->setText(path); +} + +ProxyManager::ProxyParams ProxyDialog::CurrentParams() const +{ + ProxyManager::ProxyParams params = ProxyManager::ProxyParamsFromConfig(); + params.width = static_cast(width_slider_->GetValue()); + params.height = static_cast(height_slider_->GetValue()); + params.crf = static_cast(crf_slider_->GetValue()); + params.preset = preset_combo_->currentText(); + params.include_audio = include_audio_checkbox_->isChecked(); + return params; +} + +void ProxyDialog::SaveGlobalSettings() +{ + OLIVE_CONFIG("ProxyWidth") = static_cast(width_slider_->GetValue()); + OLIVE_CONFIG("ProxyHeight") = static_cast(height_slider_->GetValue()); + OLIVE_CONFIG("ProxyCRF") = static_cast(crf_slider_->GetValue()); + OLIVE_CONFIG("ProxyPreset") = preset_combo_->currentText(); + OLIVE_CONFIG("ProxyIncludeAudio") = include_audio_checkbox_->isChecked(); + OLIVE_CONFIG("FFmpegPath") = ffmpeg_path_edit_->text().trimmed(); +} + +void ProxyDialog::RefreshFootageList() +{ + if (!footage_tree_) { + return; + } + + footage_tree_->clear(); + for (const Footage *item : footage_) { + QTreeWidgetItem *tree_item = new QTreeWidgetItem(footage_tree_); + tree_item->setText(0, item->filename()); + QString state = ProxyManager::ProxyStateToString(item->proxy_state()); + if (item->has_custom_proxy_params()) { + state = tr("%1 (custom settings)").arg(state); + } + tree_item->setText(1, state); + } +} + +void ProxyDialog::GenerateProxies() +{ + if (!ProxyManager::instance()) { + qWarning() << "ProxyDialog::GenerateProxies: ProxyManager unavailable"; + return; + } + + for (Footage *item : footage_) { + const VideoParams video = item->GetFirstEnabledVideoStream(); + if (!video.is_valid()) { + qWarning() + << "ProxyDialog::GenerateProxies: skipping item with no valid video stream" + << item->filename(); + continue; + } + + const ProxyManager::ProxyParams params = + custom_params_checkbox_->isChecked() ? CurrentParams() + : item->GetEffectiveProxyParams(); + const ProxyManager::Proxy proxy = + ProxyManager::instance()->GetOrStartProxy( + item->project()->cache_path(), item->filename(), + video.stream_index(), params); + item->SetProxy(proxy.filename, proxy.state, video.stream_index(), + params.version, true); + item->InvalidateAll(Footage::kFilenameInput); + } + + RefreshFootageList(); +} + +void ProxyDialog::DeleteProxies() +{ + for (Footage *item : footage_) { + if (item->proxy_path().isEmpty()) { + continue; + } + + QFile::remove(item->proxy_path()); + QFile::remove(ProxyManager::GetWorkingProxyFilename(item->proxy_path())); + item->ClearProxy(); + item->InvalidateAll(Footage::kFilenameInput); + } + + RefreshFootageList(); +} + +void ProxyDialog::BrowseForFFmpeg() +{ + const QString file = + QFileDialog::getOpenFileName(this, tr("Select ffmpeg Executable")); + if (!file.isEmpty()) { + ffmpeg_path_edit_->setText(file); + } +} + +} diff --git a/app/dialog/proxy/proxydialog.h b/app/dialog/proxy/proxydialog.h new file mode 100644 index 000000000..f5ce050f1 --- /dev/null +++ b/app/dialog/proxy/proxydialog.h @@ -0,0 +1,101 @@ +/* + * Oak Video Editor - Non-Linear Video Editor + * Copyright (C) 2026 Oak Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef PROXYDIALOG_H +#define PROXYDIALOG_H + +#include +#include +#include +#include +#include + +#include "codec/proxymanager.h" +#include "node/project/footage/footage.h" +#include "widget/slider/integerslider.h" + +namespace olive +{ + +class ProxyDialog : public QDialog { + Q_OBJECT +public: + ProxyDialog(QWidget *parent, const QVector &footage = {}); + + virtual void accept() override; + + int ProxyWidth() const; + + int ProxyHeight() const; + + int ProxyCRF() const; + + QString ProxyPreset() const; + + bool ProxyIncludeAudio() const; + + QString FFmpegPath() const; + + void SetProxyWidth(int width); + + void SetProxyHeight(int height); + + void SetProxyCRF(int crf); + + void SetProxyPreset(const QString &preset); + + void SetProxyIncludeAudio(bool include_audio); + + void SetFFmpegPath(const QString &path); + +private: + ProxyManager::ProxyParams CurrentParams() const; + + void SaveGlobalSettings(); + + void RefreshFootageList(); + + QVector footage_; + + QTreeWidget *footage_tree_; + + QCheckBox *custom_params_checkbox_; + + IntegerSlider *width_slider_; + + IntegerSlider *height_slider_; + + IntegerSlider *crf_slider_; + + QComboBox *preset_combo_; + + QCheckBox *include_audio_checkbox_; + + QLineEdit *ffmpeg_path_edit_; + +private slots: + void GenerateProxies(); + + void DeleteProxies(); + + void BrowseForFFmpeg(); +}; + +} + +#endif // PROXYDIALOG_H diff --git a/app/widget/projectexplorer/projectexplorer.cpp b/app/widget/projectexplorer/projectexplorer.cpp index 21421f165..4c14cb9a9 100644 --- a/app/widget/projectexplorer/projectexplorer.cpp +++ b/app/widget/projectexplorer/projectexplorer.cpp @@ -33,6 +33,7 @@ #include "common/define.h" #include "core.h" #include "dialog/footageproperties/footageproperties.h" +#include "dialog/proxy/proxydialog.h" #include "dialog/sequence/sequence.h" #include "projectexplorerundo.h" #include "codec/proxymanager.h" @@ -470,6 +471,11 @@ void ProjectExplorer::ShowContextMenu() })); connect(delete_proxy, &QAction::triggered, this, &ProjectExplorer::DeleteProxiesForSelectedFootage); + + QAction *proxy_settings = + proxy_menu->addAction(tr("Proxy Settings...")); + connect(proxy_settings, &QAction::triggered, this, + &ProjectExplorer::ShowProxyDialogForSelectedFootage); } Q_UNUSED(all_items_are_footage_or_sequence) @@ -690,6 +696,12 @@ void ProjectExplorer::DeleteProxiesForSelectedFootage() } } +void ProjectExplorer::ShowProxyDialogForSelectedFootage() +{ + ProxyDialog d(this, GetSelectedProxyFootage(context_menu_items_)); + d.exec(); +} + void ProjectExplorer::ViewSelectionChanged() { QItemSelectionModel *model = static_cast(sender()); diff --git a/app/widget/projectexplorer/projectexplorer.h b/app/widget/projectexplorer/projectexplorer.h index 85291444b..9ef43a418 100644 --- a/app/widget/projectexplorer/projectexplorer.h +++ b/app/widget/projectexplorer/projectexplorer.h @@ -198,6 +198,8 @@ private slots: void DeleteProxiesForSelectedFootage(); + void ShowProxyDialogForSelectedFootage(); + void ViewSelectionChanged(); }; diff --git a/app/widget/timelinewidget/timelinewidget.cpp b/app/widget/timelinewidget/timelinewidget.cpp index f7636ee0d..eacea6815 100644 --- a/app/widget/timelinewidget/timelinewidget.cpp +++ b/app/widget/timelinewidget/timelinewidget.cpp @@ -40,6 +40,7 @@ #include "codec/proxymanager.h" #include "core.h" #include "common/range.h" +#include "dialog/proxy/proxydialog.h" #include "dialog/sequence/sequence.h" #include "dialog/speedduration/speeddurationdialog.h" #include "node/block/transition/transition.h" @@ -1236,6 +1237,12 @@ void TimelineWidget::DeleteProxiesForSelectedClips() } } +void TimelineWidget::ShowProxyDialogForSelectedClips() +{ + ProxyDialog d(this, GetSelectedProxyFootage(selected_blocks_)); + d.exec(); +} + void TimelineWidget::RecordingCallback(const QString &filename, const TimeRange &time, const Track::Reference &track) @@ -1784,6 +1791,11 @@ void TimelineWidget::ShowContextMenu() })); connect(delete_proxy, &QAction::triggered, this, &TimelineWidget::DeleteProxiesForSelectedClips); + + QAction *proxy_settings = + proxy_menu->addAction(tr("Proxy Settings...")); + connect(proxy_settings, &QAction::triggered, this, + &TimelineWidget::ShowProxyDialogForSelectedClips); } if (clip->connected_viewer()) { diff --git a/app/widget/timelinewidget/timelinewidget.h b/app/widget/timelinewidget/timelinewidget.h index d842955c1..dee2f56b9 100644 --- a/app/widget/timelinewidget/timelinewidget.h +++ b/app/widget/timelinewidget/timelinewidget.h @@ -117,6 +117,8 @@ public: void DeleteProxiesForSelectedClips(); + void ShowProxyDialogForSelectedClips(); + void RecordingCallback(const QString &filename, const TimeRange &time, const Track::Reference &track); diff --git a/app/window/mainwindow/mainmenu.cpp b/app/window/mainwindow/mainmenu.cpp index 90f257b57..3de2d1173 100644 --- a/app/window/mainwindow/mainmenu.cpp +++ b/app/window/mainwindow/mainmenu.cpp @@ -30,6 +30,7 @@ #include "core.h" #include "dialog/actionsearch/actionsearch.h" #include "dialog/diskcache/diskcachedialog.h" +#include "dialog/proxy/proxydialog.h" #include "dialog/task/task.h" #include "panel/panelmanager.h" #include "tool/tool.h" @@ -362,8 +363,10 @@ MainMenu::MainMenu(MainWindow *parent) tools_proxy_settings_item_ = new QAction(this); Menu::ConformItem(tools_proxy_settings_item_, "proxysettings"); - connect(tools_proxy_settings_item_, &QAction::triggered, this, - []() { Core::instance()->DialogPreferencesShow(3); }); + connect(tools_proxy_settings_item_, &QAction::triggered, this, [this]() { + ProxyDialog d(this); + d.exec(); + }); tools_menu_->addAction(tools_proxy_settings_item_); tools_preferences_item_ = tools_menu_->AddItem( diff --git a/tests/gtest/CMakeLists.txt b/tests/gtest/CMakeLists.txt index a66b0fdde..ad60f8a42 100644 --- a/tests/gtest/CMakeLists.txt +++ b/tests/gtest/CMakeLists.txt @@ -45,6 +45,7 @@ add_executable(olive-gtest viewer_display_repro_test.cpp project_serializer_test.cpp proxy_manager_test.cpp + proxy_dialog_test.cpp timeline_marker_test.cpp undo_stack_test.cpp plugin_support_test.cpp diff --git a/tests/gtest/proxy_dialog_test.cpp b/tests/gtest/proxy_dialog_test.cpp new file mode 100644 index 000000000..264be7ec0 --- /dev/null +++ b/tests/gtest/proxy_dialog_test.cpp @@ -0,0 +1,72 @@ +#include + +#include "config/config.h" +#include "dialog/proxy/proxydialog.h" +#include "node/project/footage/footage.h" + +namespace +{ + +QVariant ProxyDialogConfigValue(const char *key) +{ + return olive::Config::Current()[QString::fromUtf8(key)]; +} + +} // namespace + +TEST(ProxyDialog, ConstructsInGlobalModeWithNullParent) +{ + olive::ProxyDialog dialog(nullptr); + + // The global settings editors must reflect the current config values + EXPECT_EQ(dialog.ProxyWidth(), + ProxyDialogConfigValue("ProxyWidth").value()); + EXPECT_EQ(dialog.ProxyHeight(), + ProxyDialogConfigValue("ProxyHeight").value()); + EXPECT_EQ(dialog.ProxyCRF(), + ProxyDialogConfigValue("ProxyCRF").value()); + EXPECT_EQ(dialog.ProxyPreset(), + ProxyDialogConfigValue("ProxyPreset").toString()); + EXPECT_EQ(dialog.ProxyIncludeAudio(), + ProxyDialogConfigValue("ProxyIncludeAudio").toBool()); + EXPECT_EQ(dialog.FFmpegPath(), + ProxyDialogConfigValue("FFmpegPath").toString()); +} + +TEST(ProxyDialog, ConstructsWithFootageList) +{ + olive::Footage footage; + const QVector items = { &footage }; + + olive::ProxyDialog dialog(nullptr, items); + SUCCEED(); +} + +TEST(ProxyDialog, AcceptSavesGlobalSettingsToConfig) +{ + const int old_width = ProxyDialogConfigValue("ProxyWidth").value(); + const bool old_include_audio = + ProxyDialogConfigValue("ProxyIncludeAudio").toBool(); + const QString old_ffmpeg_path = + ProxyDialogConfigValue("FFmpegPath").toString(); + + { + olive::ProxyDialog dialog(nullptr); + dialog.SetProxyWidth(640); + dialog.SetProxyIncludeAudio(!old_include_audio); + dialog.SetFFmpegPath(QStringLiteral("/tmp/oak-test-ffmpeg")); + dialog.accept(); + } + + EXPECT_EQ(ProxyDialogConfigValue("ProxyWidth").value(), 640); + EXPECT_EQ(ProxyDialogConfigValue("ProxyIncludeAudio").toBool(), + !old_include_audio); + EXPECT_EQ(ProxyDialogConfigValue("FFmpegPath").toString(), + QStringLiteral("/tmp/oak-test-ffmpeg")); + + // Restore previous config values so other tests are unaffected + olive::Config::Current()[QStringLiteral("ProxyWidth")] = old_width; + olive::Config::Current()[QStringLiteral("ProxyIncludeAudio")] = + old_include_audio; + olive::Config::Current()[QStringLiteral("FFmpegPath")] = old_ffmpeg_path; +}