diff --git a/app/core.cpp b/app/core.cpp
index c9d47386e..f0d7d2f7f 100644
--- a/app/core.cpp
+++ b/app/core.cpp
@@ -46,6 +46,7 @@
#ifdef USE_OTIO
#include "dialog/otioproperties/otiopropertiesdialog.h"
#endif
+#include "dialog/projectproperties/projectproperties.h"
#include "dialog/sequence/sequence.h"
#include "dialog/task/task.h"
#include "dialog/preferences/preferences.h"
@@ -367,6 +368,21 @@ void Core::DialogPreferencesShow()
pd.exec();
}
+void Core::DialogProjectPropertiesShow()
+{
+ Project *proj = GetActiveProject();
+
+ if (proj) {
+ ProjectPropertiesDialog ppd(proj, main_window_);
+ ppd.exec();
+ } else {
+ QMessageBox::critical(main_window_,
+ tr("No Active Project"),
+ tr("No project is currently open to set the properties for"),
+ QMessageBox::Ok);
+ }
+}
+
void Core::DialogExportShow()
{
ViewerOutput* viewer = GetSequenceToExport();
diff --git a/app/core.h b/app/core.h
index de7ac21f3..653769af6 100644
--- a/app/core.h
+++ b/app/core.h
@@ -391,6 +391,11 @@ public slots:
*/
void DialogPreferencesShow();
+ /**
+ * @brief Show Project Properties dialog
+ */
+ void DialogProjectPropertiesShow();
+
/**
* @brief Show Export dialog
*/
diff --git a/app/dialog/CMakeLists.txt b/app/dialog/CMakeLists.txt
index 7692472ec..a7ecf0f78 100644
--- a/app/dialog/CMakeLists.txt
+++ b/app/dialog/CMakeLists.txt
@@ -29,6 +29,7 @@ if(OpenTimelineIO_FOUND)
endif()
add_subdirectory(preferences)
add_subdirectory(progress)
+add_subdirectory(projectproperties)
add_subdirectory(rendercancel)
add_subdirectory(sequence)
add_subdirectory(speedduration)
diff --git a/app/dialog/projectproperties/CMakeLists.txt b/app/dialog/projectproperties/CMakeLists.txt
new file mode 100644
index 000000000..b45092bf6
--- /dev/null
+++ b/app/dialog/projectproperties/CMakeLists.txt
@@ -0,0 +1,22 @@
+# Olive - Non-Linear Video Editor
+# Copyright (C) 2020 Olive 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/projectproperties/projectproperties.h
+ dialog/projectproperties/projectproperties.cpp
+ PARENT_SCOPE
+)
diff --git a/app/dialog/projectproperties/projectproperties.cpp b/app/dialog/projectproperties/projectproperties.cpp
new file mode 100644
index 000000000..2c75edc9e
--- /dev/null
+++ b/app/dialog/projectproperties/projectproperties.cpp
@@ -0,0 +1,255 @@
+/***
+
+ Olive - Non-Linear Video Editor
+ Copyright (C) 2020 Olive 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 "projectproperties.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "common/filefunctions.h"
+#include "common/ocioutils.h"
+#include "config/config.h"
+#include "core.h"
+#include "node/color/colormanager/colormanager.h"
+#include "render/diskmanager.h"
+
+namespace olive {
+
+#define super QDialog
+
+ProjectPropertiesDialog::ProjectPropertiesDialog(Project* p, QWidget *parent) :
+ super(parent),
+ working_project_(p),
+ ocio_config_is_valid_(true)
+{
+ QVBoxLayout* layout = new QVBoxLayout(this);
+
+ setWindowTitle(tr("Project Properties for '%1'").arg(working_project_->name()));
+
+ QTabWidget* tabs = new QTabWidget;
+ layout->addWidget(tabs);
+
+ {
+ // Color management group
+ QWidget* color_group = new QWidget();
+
+ QVBoxLayout* color_outer_layout = new QVBoxLayout(color_group);
+
+ QGridLayout* color_layout = new QGridLayout();
+ color_outer_layout->addLayout(color_layout);
+
+ int row = 0;
+
+ color_layout->addWidget(new QLabel(tr("OpenColorIO Configuration:")), row, 0);
+
+ ocio_filename_ = new QLineEdit();
+ ocio_filename_->setPlaceholderText(tr("(default)"));
+ color_layout->addWidget(ocio_filename_, row, 1);
+
+ row++;
+
+ color_layout->addWidget(new QLabel(tr("Default Input Color Space:")), row, 0);
+
+ default_input_colorspace_ = new QComboBox();
+ color_layout->addWidget(default_input_colorspace_, row, 1, 1, 2);
+
+ row++;
+
+ QPushButton* browse_btn = new QPushButton(tr("Browse"));
+ color_layout->addWidget(browse_btn, 0, 2);
+ connect(browse_btn, &QPushButton::clicked, this, &ProjectPropertiesDialog::BrowseForOCIOConfig);
+
+ ocio_filename_->setText(working_project_->color_manager()->GetConfigFilename());
+
+ connect(ocio_filename_, &QLineEdit::textChanged, this, &ProjectPropertiesDialog::OCIOFilenameUpdated);
+ OCIOFilenameUpdated();
+
+ tabs->addTab(color_group, tr("Color Management"));
+
+ color_outer_layout->addStretch();
+ }
+
+ {
+ // Cache group
+ QWidget* cache_group = new QWidget();
+
+ QVBoxLayout* cache_layout = new QVBoxLayout(cache_group);
+
+ QButtonGroup* disk_cache_btn_group = new QButtonGroup();
+
+ // Create radio buttons and add to widget and button group
+ disk_cache_radios_[ProjectSettingsNode::kCacheUseDefaultLocation] = new QRadioButton(tr("Use Default Location"));
+ disk_cache_radios_[ProjectSettingsNode::kCacheStoreAlongsideProject] = new QRadioButton(tr("Store Alongside Project"));
+ disk_cache_radios_[ProjectSettingsNode::kCacheCustomPath] = new QRadioButton(tr("Use Custom Location:"));
+ for (int i=0; iaddButton(disk_cache_radios_[i]);
+ cache_layout->addWidget(disk_cache_radios_[i]);
+ }
+
+ // Create custom cache path widget
+ custom_cache_path_ = new PathWidget(working_project_->settings()->GetCustomCachePath(), this);
+ custom_cache_path_->setEnabled(false);
+ cache_layout->addWidget(custom_cache_path_);
+
+ // Ensure custom cache path "enabled" is tied to the radio button being checked
+ connect(disk_cache_radios_[ProjectSettingsNode::kCacheCustomPath], &QRadioButton::toggled, custom_cache_path_, &PathWidget::setEnabled);
+
+ // Check the radio button that should currently be active
+ disk_cache_radios_[working_project_->settings()->GetCacheSetting()]->setChecked(true);
+
+ // Add disk cache settings button
+ QPushButton* disk_cache_settings_btn = new QPushButton(tr("Disk Cache Settings"));
+ connect(disk_cache_settings_btn, &QPushButton::clicked, this, &ProjectPropertiesDialog::OpenDiskCacheSettings);
+ cache_layout->addWidget(disk_cache_settings_btn);
+
+ tabs->addTab(cache_group, tr("Disk Cache"));
+ }
+
+ QDialogButtonBox* dialog_btns = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel,
+ Qt::Horizontal);
+ layout->addWidget(dialog_btns);
+ connect(dialog_btns, &QDialogButtonBox::accepted, this, &ProjectPropertiesDialog::accept);
+ connect(dialog_btns, &QDialogButtonBox::rejected, this, &ProjectPropertiesDialog::reject);
+}
+
+void ProjectPropertiesDialog::accept()
+{
+ if (!ocio_config_is_valid_) {
+ QMessageBox mb(this);
+ mb.setWindowModality(Qt::WindowModal);
+ mb.setIcon(QMessageBox::Critical);
+ mb.setWindowTitle(tr("OpenColorIO Config Error"));
+ mb.setText(tr("Failed to set OpenColorIO configuration: %1").arg(ocio_config_error_));
+ mb.addButton(QMessageBox::Ok);
+ mb.exec();
+ return;
+ }
+
+ if (disk_cache_radios_[ProjectSettingsNode::kCacheUseDefaultLocation]->isChecked()) {
+ // Keep new cache path empty, which means default
+ } else if (disk_cache_radios_[ProjectSettingsNode::kCacheStoreAlongsideProject]->isChecked()) {
+ // Ensure alongside project path is valid
+ if (!VerifyPathAndWarnIfBad(working_project_->get_cache_alongside_project_path())) {
+ return;
+ }
+ } else {
+ // Ensure custom path is valid
+ if (!VerifyPathAndWarnIfBad(custom_cache_path_->text())) {
+ return;
+ }
+ }
+
+ if (custom_cache_path_->text() != working_project_->settings()->GetCustomCachePath()) {
+ // Check if the user is okay with invalidating the current cache
+ if (!DiskManager::ShowDiskCacheChangeConfirmationDialog(this)) {
+ return;
+ }
+
+ working_project_->settings()->SetCustomCachePath(custom_cache_path_->text());
+
+ emit DiskManager::instance()->InvalidateProject(working_project_);
+ }
+
+ // This should ripple changes throughout the graph/cache that the color config has changed, and
+ // therefore should be done after the cache path is changed
+ if (working_project_->color_manager()->GetConfigFilename() != ocio_filename_->text()) {
+ working_project_->color_manager()->SetConfigFilename(ocio_filename_->text());
+ }
+ if (working_project_->color_manager()->GetDefaultInputColorSpace() != default_input_colorspace_->currentText()) {
+ working_project_->color_manager()->SetDefaultInputColorSpace(default_input_colorspace_->currentText());
+ }
+
+ super::accept();
+}
+
+bool ProjectPropertiesDialog::VerifyPathAndWarnIfBad(const QString &path)
+{
+ if (!FileFunctions::DirectoryIsValid(path, true)) {
+ QMessageBox mb(this);
+ mb.setWindowModality(Qt::WindowModal);
+ mb.setIcon(QMessageBox::Critical);
+ mb.setWindowTitle(tr("Invalid path"));
+ mb.setText(tr("The custom cache path is invalid. Please check it and try again."));
+ mb.addButton(QMessageBox::Ok);
+ mb.exec();
+ return false;
+ }
+
+ return true;
+}
+
+void ProjectPropertiesDialog::BrowseForOCIOConfig()
+{
+ QString fn = QFileDialog::getOpenFileName(this, tr("Browse for OpenColorIO configuration"));
+ if (!fn.isEmpty()) {
+ ocio_filename_->setText(fn);
+ }
+}
+
+void ProjectPropertiesDialog::OCIOFilenameUpdated()
+{
+ default_input_colorspace_->clear();
+
+ try {
+ OCIO::ConstConfigRcPtr c;
+
+ if (ocio_filename_->text().isEmpty()) {
+ c = ColorManager::GetDefaultConfig();
+ } else {
+ c = ColorManager::CreateConfigFromFile(ocio_filename_->text());
+ }
+
+ ocio_filename_->setStyleSheet(QString());
+ ocio_config_is_valid_ = true;
+
+ // List input color spaces
+ QStringList input_cs = ColorManager::ListAvailableColorspaces(c);
+
+ foreach (QString cs, input_cs) {
+ default_input_colorspace_->addItem(cs);
+
+ if (cs == working_project_->color_manager()->GetDefaultInputColorSpace()) {
+ default_input_colorspace_->setCurrentIndex(default_input_colorspace_->count()-1);
+ }
+ }
+ } catch (OCIO::Exception& e) {
+ ocio_config_is_valid_ = false;
+ ocio_filename_->setStyleSheet(QStringLiteral("QLineEdit {color: red;}"));
+ ocio_config_error_ = e.what();
+ }
+}
+
+void ProjectPropertiesDialog::OpenDiskCacheSettings()
+{
+ if (disk_cache_radios_[ProjectSettingsNode::kCacheUseDefaultLocation]->isChecked()) {
+ DiskManager::instance()->ShowDiskCacheSettingsDialog(DiskManager::instance()->GetDefaultCacheFolder(), this);
+ } else if (disk_cache_radios_[ProjectSettingsNode::kCacheStoreAlongsideProject]->isChecked()) {
+ DiskManager::instance()->ShowDiskCacheSettingsDialog(working_project_->get_cache_alongside_project_path(), this);
+ } else {
+ DiskManager::instance()->ShowDiskCacheSettingsDialog(custom_cache_path_->text(), this);
+ }
+}
+
+}
diff --git a/app/dialog/projectproperties/projectproperties.h b/app/dialog/projectproperties/projectproperties.h
new file mode 100644
index 000000000..e6963e541
--- /dev/null
+++ b/app/dialog/projectproperties/projectproperties.h
@@ -0,0 +1,74 @@
+/***
+
+ Olive - Non-Linear Video Editor
+ Copyright (C) 2020 Olive 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 PROJECTPROPERTIESDIALOG_H
+#define PROJECTPROPERTIESDIALOG_H
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "node/project/project.h"
+#include "widget/path/pathwidget.h"
+
+namespace olive {
+
+class ProjectPropertiesDialog : public QDialog
+{
+ Q_OBJECT
+public:
+ ProjectPropertiesDialog(Project *p, QWidget* parent);
+
+public slots:
+ virtual void accept() override;
+
+private:
+ bool VerifyPathAndWarnIfBad(const QString &path);
+
+ Project* working_project_;
+
+ QLineEdit* ocio_filename_;
+
+ QComboBox* default_input_colorspace_;
+
+ bool ocio_config_is_valid_;
+
+ QString ocio_config_error_;
+
+ PathWidget* custom_cache_path_;
+
+ static const int kDiskCacheRadioCount = 3;
+ QRadioButton *disk_cache_radios_[kDiskCacheRadioCount];
+
+private slots:
+ void BrowseForOCIOConfig();
+
+ void OCIOFilenameUpdated();
+
+ void OpenDiskCacheSettings();
+
+};
+
+}
+
+#endif // PROJECTPROPERTIESDIALOG_H
diff --git a/app/node/project/project.cpp b/app/node/project/project.cpp
index 9641669cd..d244b41ed 100644
--- a/app/node/project/project.cpp
+++ b/app/node/project/project.cpp
@@ -320,6 +320,15 @@ bool Project::is_new() const
return !is_modified_ && filename_.isEmpty();
}
+QString Project::get_cache_alongside_project_path() const
+{
+ if (!filename_.isEmpty()) {
+ // Non-translated string so the path doesn't change if the language does
+ return QFileInfo(filename_).dir().filePath(QStringLiteral("cache"));
+ }
+ return QString();
+}
+
QString Project::cache_path() const
{
ProjectSettingsNode::CacheSetting setting = settings_->GetCacheSetting();
@@ -330,7 +339,6 @@ QString Project::cache_path() const
case ProjectSettingsNode::kCacheCustomPath:
{
QString cache_path = settings_->GetCustomCachePath();
-
if (cache_path.isEmpty()) {
return cache_path;
}
@@ -338,8 +346,9 @@ QString Project::cache_path() const
}
case ProjectSettingsNode::kCacheStoreAlongsideProject:
{
- if (!filename_.isEmpty()) {
- return QFileInfo(filename_).path();
+ QString alongside = get_cache_alongside_project_path();
+ if (!alongside.isEmpty()) {
+ return alongside;
}
break;
}
diff --git a/app/node/project/project.h b/app/node/project/project.h
index 2565e3697..11f31ee41 100644
--- a/app/node/project/project.h
+++ b/app/node/project/project.h
@@ -73,6 +73,7 @@ public:
bool is_new() const;
+ QString get_cache_alongside_project_path() const;
QString cache_path() const;
const QUuid& GetUuid() const
diff --git a/app/window/mainwindow/mainmenu.cpp b/app/window/mainwindow/mainmenu.cpp
index cb3322f67..3492f9442 100644
--- a/app/window/mainwindow/mainmenu.cpp
+++ b/app/window/mainwindow/mainmenu.cpp
@@ -69,6 +69,8 @@ MainMenu::MainMenu(MainWindow *parent) :
file_close_all_projects_item_ = file_menu_->AddItem("closeallproj", Core::instance(), static_cast(&Core::CloseAllProjects));
file_close_all_except_item_ = file_menu_->AddItem("closeallexcept", Core::instance(), &Core::CloseAllExceptActiveProject);
file_menu_->addSeparator();
+ file_project_properties_item_ = file_menu_->AddItem("projectproperties", Core::instance(), &Core::DialogProjectPropertiesShow, tr("Shift+F10"));
+ file_menu_->addSeparator();
file_exit_item_ = file_menu_->AddItem("exit", parent, &MainWindow::close);
//
@@ -696,6 +698,7 @@ void MainMenu::Retranslate()
file_export_menu_->setTitle(tr("&Export"));
file_export_media_item_->setText(tr("&Media..."));
file_close_all_projects_item_->setText(tr("Close All Projects"));
+ file_project_properties_item_->setText(tr("Project Properties"));
file_exit_item_->setText(tr("E&xit"));
// Edit menu
diff --git a/app/window/mainwindow/mainmenu.h b/app/window/mainwindow/mainmenu.h
index ff038e64a..748e7159f 100644
--- a/app/window/mainwindow/mainmenu.h
+++ b/app/window/mainwindow/mainmenu.h
@@ -210,6 +210,7 @@ private:
QAction* file_close_project_item_;
QAction* file_close_all_projects_item_;
QAction* file_close_all_except_item_;
+ QAction* file_project_properties_item_;
QAction* file_exit_item_;
Menu* edit_menu_;