core: implemented yes/no to all when closing multiple modified projects

This commit is contained in:
itsmattkc
2020-04-19 03:29:39 +10:00
parent d232e035f5
commit 63c194896d
9 changed files with 157 additions and 57 deletions
+122 -39
View File
@@ -274,6 +274,17 @@ const QStringList &Core::GetRecentProjects() const
return recent_projects_; return recent_projects_;
} }
ProjectPtr Core::GetSharedPtrFromProject(Project *project) const
{
foreach (ProjectPtr p, open_projects_) {
if (p.get() == project) {
return p;
}
}
return nullptr;
}
void Core::SetTool(const Tool::Item &tool) void Core::SetTool(const Tool::Item &tool)
{ {
tool_ = tool; tool_ = tool;
@@ -328,7 +339,7 @@ void Core::DialogPreferencesShow()
void Core::DialogProjectPropertiesShow() void Core::DialogProjectPropertiesShow()
{ {
ProjectPropertiesDialog ppd(GetActiveProject(), main_window_); ProjectPropertiesDialog ppd(GetActiveProject().get(), main_window_);
ppd.exec(); ppd.exec();
} }
@@ -357,7 +368,7 @@ void Core::CreateNewFolder()
if (active_project_panel == nullptr // Check that we found a Project panel if (active_project_panel == nullptr // Check that we found a Project panel
|| (active_project = active_project_panel->project()) == nullptr) { // and that we could find an active Project || (active_project = active_project_panel->project()) == nullptr) { // and that we could find an active Project
QMessageBox::critical(main_window_, tr("Failed to create new folder"), tr("Failed to find active Project panel")); QMessageBox::critical(main_window_, tr("Failed to create new folder"), tr("Failed to find active project"));
return; return;
} }
@@ -383,15 +394,15 @@ void Core::CreateNewFolder()
void Core::CreateNewSequence() void Core::CreateNewSequence()
{ {
Project* active_project = GetActiveProject(); ProjectPtr active_project = GetActiveProject();
if (!active_project) { if (!active_project) {
QMessageBox::critical(main_window_, tr("Failed to create new sequence"), tr("Failed to find active Project panel")); QMessageBox::critical(main_window_, tr("Failed to create new sequence"), tr("Failed to find active project"));
return; return;
} }
// Create new sequence // Create new sequence
SequencePtr new_sequence = CreateNewSequenceForProject(active_project); SequencePtr new_sequence = CreateNewSequenceForProject(active_project.get());
// Set all defaults for the sequence // Set all defaults for the sequence
new_sequence->set_default_parameters(); new_sequence->set_default_parameters();
@@ -429,7 +440,7 @@ void Core::AddOpenProject(ProjectPtr p)
// If we currently have an empty project, close it first // If we currently have an empty project, close it first
if (!open_projects_.isEmpty() && open_projects_.last()->is_new()) { if (!open_projects_.isEmpty() && open_projects_.last()->is_new()) {
CloseProject(open_projects_.last().get(), false); CloseProject(open_projects_.last(), false);
} }
connect(p.get(), &Project::ModifiedChanged, this, &Core::ProjectWasModified); connect(p.get(), &Project::ModifiedChanged, this, &Core::ProjectWasModified);
@@ -496,6 +507,7 @@ void Core::DeclareTypesForQt()
qRegisterMetaType<Decoder::RetrieveState>(); qRegisterMetaType<Decoder::RetrieveState>();
qRegisterMetaType<TimeRange>(); qRegisterMetaType<TimeRange>();
qRegisterMetaType<Color>(); qRegisterMetaType<Color>();
qRegisterMetaType<ProjectPtr>();
} }
void Core::StartGUI(bool full_screen) void Core::StartGUI(bool full_screen)
@@ -545,7 +557,7 @@ void Core::StartGUI(bool full_screen)
autorecovery_timer_.start(); autorecovery_timer_.start();
} }
void Core::SaveProjectInternal(Project *project) void Core::SaveProjectInternal(ProjectPtr project)
{ {
// Create save manager // Create save manager
ProjectSaveManager* psm = new ProjectSaveManager(project); ProjectSaveManager* psm = new ProjectSaveManager(project);
@@ -566,22 +578,22 @@ void Core::SaveAutorecovery()
} }
} }
void Core::ProjectSaveSucceeded(Project* p) void Core::ProjectSaveSucceeded(ProjectPtr p)
{ {
PushRecentlyOpenedProject(p->filename()); PushRecentlyOpenedProject(p->filename());
p->set_modified(false); p->set_modified(false);
} }
Project *Core::GetActiveProject() const ProjectPtr Core::GetActiveProject() const
{ {
ProjectPanel* active_project_panel = PanelManager::instance()->MostRecentlyFocused<ProjectPanel>(); ProjectPanel* active_project_panel = PanelManager::instance()->MostRecentlyFocused<ProjectPanel>();
if (active_project_panel) { if (active_project_panel && active_project_panel->project()) {
return active_project_panel->project(); return GetSharedPtrFromProject(active_project_panel->project());
} else {
return nullptr;
} }
return nullptr;
} }
ProjectViewModel *Core::GetActiveProjectModel() const ProjectViewModel *Core::GetActiveProjectModel() const
@@ -636,7 +648,7 @@ QString Core::PasteStringFromClipboard()
bool Core::SaveActiveProject() bool Core::SaveActiveProject()
{ {
Project* active_project = GetActiveProject(); ProjectPtr active_project = GetActiveProject();
if (active_project) { if (active_project) {
return SaveProject(active_project); return SaveProject(active_project);
@@ -647,7 +659,7 @@ bool Core::SaveActiveProject()
bool Core::SaveActiveProjectAs() bool Core::SaveActiveProjectAs()
{ {
Project* active_project = GetActiveProject(); ProjectPtr active_project = GetActiveProject();
if (active_project) { if (active_project) {
return SaveProjectAs(active_project); return SaveProjectAs(active_project);
@@ -659,7 +671,7 @@ bool Core::SaveActiveProjectAs()
bool Core::SaveAllProjects() bool Core::SaveAllProjects()
{ {
foreach (ProjectPtr p, open_projects_) { foreach (ProjectPtr p, open_projects_) {
if (!SaveProject(p.get())) { if (!SaveProject(p)) {
return false; return false;
} }
} }
@@ -674,12 +686,12 @@ bool Core::CloseActiveProject()
bool Core::CloseAllExceptActiveProject() bool Core::CloseAllExceptActiveProject()
{ {
Project* active_proj = GetActiveProject(); ProjectPtr active_proj = GetActiveProject();
QList<ProjectPtr> copy = open_projects_; QList<ProjectPtr> copy = open_projects_;
foreach (ProjectPtr p, copy) { foreach (ProjectPtr p, copy) {
if (p.get() != active_proj) { if (p != active_proj) {
if (!CloseProject(p.get(), true)) { if (!CloseProject(p, true)) {
return false; return false;
} }
} }
@@ -774,7 +786,7 @@ QString Core::GetRecentProjectsFilePath()
return QDir(GetConfigurationLocation()).filePath(QStringLiteral("recent")); return QDir(GetConfigurationLocation()).filePath(QStringLiteral("recent"));
} }
bool Core::SaveProject(Project *p) bool Core::SaveProject(ProjectPtr p)
{ {
if (p->filename().isEmpty()) { if (p->filename().isEmpty()) {
return SaveProjectAs(p); return SaveProjectAs(p);
@@ -785,7 +797,7 @@ bool Core::SaveProject(Project *p)
} }
} }
bool Core::SaveProjectAs(Project *p) bool Core::SaveProjectAs(ProjectPtr p)
{ {
QString fn = QFileDialog::getSaveFileName(main_window_, QString fn = QFileDialog::getSaveFileName(main_window_,
tr("Save Project As"), tr("Save Project As"),
@@ -908,34 +920,81 @@ void Core::OpenProjectFromRecentList(int index)
} }
} }
bool Core::CloseProject(Project *p, bool auto_open_new) bool Core::CloseProject(ProjectPtr p, bool auto_open_new)
{
CloseProjectBehavior b = kCloseProjectOnlyOne;
return CloseProject(p, auto_open_new, b);
}
bool Core::CloseProject(ProjectPtr p, bool auto_open_new, CloseProjectBehavior &confirm_behavior)
{ {
for (int i=0;i<open_projects_.size();i++) { for (int i=0;i<open_projects_.size();i++) {
if (open_projects_.at(i).get() == p) { if (open_projects_.at(i) == p) {
if (p->is_modified()) { if (p->is_modified() && confirm_behavior != kCloseProjectDontSave) {
QMessageBox mb(main_window_);
mb.setIcon(QMessageBox::Question); bool save_this_project;
mb.setWindowTitle(tr("Unsaved Changes"));
mb.setText(tr("The project '%1' has unsaved changes. Would you like to save them?")
.arg(p->name()));
QPushButton* yes_btn = mb.addButton(tr("Save"), QMessageBox::YesRole); if (confirm_behavior == kCloseProjectAsk || confirm_behavior == kCloseProjectOnlyOne) {
mb.addButton(tr("Don't Save"), QMessageBox::NoRole); QMessageBox mb(main_window_);
QPushButton* cancel_btn = mb.addButton(QMessageBox::Cancel);
mb.exec(); mb.setIcon(QMessageBox::Question);
mb.setWindowTitle(tr("Unsaved Changes"));
mb.setText(tr("The project '%1' has unsaved changes. Would you like to save them?")
.arg(p->name()));
if (mb.clickedButton() == cancel_btn QPushButton* yes_btn = mb.addButton(tr("Save"), QMessageBox::YesRole);
|| (mb.clickedButton() == yes_btn && !SaveActiveProject())) {
// Don't close if the user clicked cancel on this messagebox OR they cancelled a save as operation QPushButton* yes_to_all_btn;
if (confirm_behavior == kCloseProjectOnlyOne) {
yes_to_all_btn = nullptr;
} else {
yes_to_all_btn = mb.addButton(tr("Save All"), QMessageBox::YesRole);
}
mb.addButton(tr("Don't Save"), QMessageBox::NoRole);
QPushButton* no_to_all_btn;
if (confirm_behavior == kCloseProjectOnlyOne) {
no_to_all_btn = nullptr;
} else {
no_to_all_btn = mb.addButton(tr("Don't Save All"), QMessageBox::NoRole);
}
QPushButton* cancel_btn = mb.addButton(QMessageBox::Cancel);
mb.exec();
if (mb.clickedButton() == cancel_btn) {
// Stop closing projects if the user clicked cancel
return false;
} else if (mb.clickedButton() == yes_to_all_btn) {
// Set flag that other CloseProject commands are going to use
confirm_behavior = kCloseProjectSave;
} else if (mb.clickedButton() == no_to_all_btn) {
// Set flag that other CloseProject commands are going to use
confirm_behavior = kCloseProjectDontSave;
}
save_this_project = (mb.clickedButton() == yes_btn || mb.clickedButton() == yes_to_all_btn);
} else {
// We must be saving this project
save_this_project = true;
}
if (save_this_project && !SaveProject(p)) {
// The save failed, stop closing projects
return false; return false;
} }
} }
disconnect(p, &Project::ModifiedChanged, this, &Core::ProjectWasModified); // For safety, the undo stack is cleared so no commands try to affect a freed project
emit ProjectClosed(p); undo_stack_.clear();
disconnect(p.get(), &Project::ModifiedChanged, this, &Core::ProjectWasModified);
emit ProjectClosed(p.get());
open_projects_.removeAt(i); open_projects_.removeAt(i);
break; break;
} }
@@ -953,10 +1012,34 @@ bool Core::CloseAllProjects(bool auto_open_new)
{ {
QList<ProjectPtr> copy = open_projects_; QList<ProjectPtr> copy = open_projects_;
// See how many projects are modified so we can set "behavior" correctly
// (i.e. whether to show "Yes/No To All" buttons or not)
int modified_count = 0;
foreach (ProjectPtr p, copy) { foreach (ProjectPtr p, copy) {
if (!CloseProject(p.get(), auto_open_new)) { if (p->is_modified()) {
modified_count++;
}
}
CloseProjectBehavior behavior;
if (modified_count > 1) {
behavior = kCloseProjectAsk;
} else {
behavior = kCloseProjectOnlyOne;
}
foreach (ProjectPtr p, copy) {
// If this is the only remaining project and the user hasn't chose "yes/no to all", hide those buttons
if (modified_count == 1 && behavior == kCloseProjectAsk) {
behavior = kCloseProjectOnlyOne;
}
if (!CloseProject(p, auto_open_new, behavior)) {
return false; return false;
} }
modified_count--;
} }
return true; return true;
+19 -6
View File
@@ -124,6 +124,11 @@ public:
*/ */
const QStringList& GetRecentProjects() const; const QStringList& GetRecentProjects() const;
/**
* @brief Convenience function to retrieve a Project's shared pointer
*/
ProjectPtr GetSharedPtrFromProject(Project* project) const;
/** /**
* @brief Get the currently active project * @brief Get the currently active project
* *
@@ -134,7 +139,7 @@ public:
* *
* The active Project file, or nullptr if the heuristic couldn't find one. * The active Project file, or nullptr if the heuristic couldn't find one.
*/ */
Project* GetActiveProject() const; ProjectPtr GetActiveProject() const;
ProjectViewModel* GetActiveProjectModel() const; ProjectViewModel* GetActiveProjectModel() const;
Folder* GetSelectedFolderInActiveProject() const; Folder* GetSelectedFolderInActiveProject() const;
@@ -206,10 +211,18 @@ public:
*/ */
void OpenProjectFromRecentList(int index); void OpenProjectFromRecentList(int index);
enum CloseProjectBehavior {
kCloseProjectOnlyOne,
kCloseProjectAsk,
kCloseProjectSave,
kCloseProjectDontSave
};
/** /**
* @brief Closes a project * @brief Closes a project
*/ */
bool CloseProject(Project* p, bool auto_open_new); bool CloseProject(ProjectPtr p, bool auto_open_new, CloseProjectBehavior& confirm_behavior);
bool CloseProject(ProjectPtr p, bool auto_open_new);
/** /**
* @brief Closes all open projects * @brief Closes all open projects
@@ -365,12 +378,12 @@ private:
/** /**
* @brief Saves a specific project * @brief Saves a specific project
*/ */
bool SaveProject(Project* p); bool SaveProject(ProjectPtr p);
/** /**
* @brief Performs a "save as" on a specific project * @brief Performs a "save as" on a specific project
*/ */
bool SaveProjectAs(Project* p); bool SaveProjectAs(ProjectPtr p);
/** /**
* @brief Adds a filename to the top of the recently opened projects list (or moves it if it already exists) * @brief Adds a filename to the top of the recently opened projects list (or moves it if it already exists)
@@ -401,7 +414,7 @@ private:
/** /**
* @brief Internal function for saving a project to a file * @brief Internal function for saving a project to a file
*/ */
void SaveProjectInternal(Project* project); void SaveProjectInternal(ProjectPtr project);
/** /**
* @brief Internal main window object * @brief Internal main window object
@@ -459,7 +472,7 @@ private:
private slots: private slots:
void SaveAutorecovery(); void SaveAutorecovery();
void ProjectSaveSucceeded(Project *p); void ProjectSaveSucceeded(ProjectPtr p);
/** /**
* @brief Adds a project to the "open projects" list * @brief Adds a project to the "open projects" list
+4 -2
View File
@@ -69,12 +69,12 @@ ProjectPanel::ProjectPanel(QWidget *parent) :
Retranslate(); Retranslate();
} }
Project *ProjectPanel::project() const Project* ProjectPanel::project() const
{ {
return explorer_->project(); return explorer_->project();
} }
void ProjectPanel::set_project(Project *p) void ProjectPanel::set_project(Project* p)
{ {
if (project()) { if (project()) {
disconnect(project(), &Project::NameChanged, this, &ProjectPanel::UpdateSubtitle); disconnect(project(), &Project::NameChanged, this, &ProjectPanel::UpdateSubtitle);
@@ -92,6 +92,8 @@ void ProjectPanel::set_project(Project *p)
UpdateSubtitle(); UpdateSubtitle();
emit ProjectNameChanged();
if (p) { if (p) {
setWindowModified(p->is_modified()); setWindowModified(p->is_modified());
} else { } else {
+2
View File
@@ -82,4 +82,6 @@ private slots:
OLIVE_NAMESPACE_EXIT OLIVE_NAMESPACE_EXIT
Q_DECLARE_METATYPE(OLIVE_NAMESPACE::ProjectPtr)
#endif // PROJECT_PANEL_H #endif // PROJECT_PANEL_H
+1 -1
View File
@@ -25,7 +25,7 @@
OLIVE_NAMESPACE_ENTER OLIVE_NAMESPACE_ENTER
ProjectSaveManager::ProjectSaveManager(Project *project) : ProjectSaveManager::ProjectSaveManager(ProjectPtr project) :
project_(project) project_(project)
{ {
SetTitle(tr("Saving '%1'").arg(project->filename())); SetTitle(tr("Saving '%1'").arg(project->filename()));
+3 -3
View File
@@ -30,16 +30,16 @@ class ProjectSaveManager : public Task
{ {
Q_OBJECT Q_OBJECT
public: public:
ProjectSaveManager(Project* project); ProjectSaveManager(ProjectPtr project);
signals: signals:
void ProjectSaveSucceeded(Project* p); void ProjectSaveSucceeded(ProjectPtr p);
protected: protected:
virtual void Action() override; virtual void Action() override;
private: private:
Project* project_; ProjectPtr project_;
}; };
+2 -2
View File
@@ -321,10 +321,10 @@ void TimelineWidget::ImportTool::DropGhosts(bool insert)
} }
if (behavior != kDWSDisable) { if (behavior != kDWSDisable) {
Project* active_project = Core::instance()->GetActiveProject(); ProjectPtr active_project = Core::instance()->GetActiveProject();
if (active_project) { if (active_project) {
SequencePtr new_sequence = Core::instance()->CreateNewSequenceForProject(active_project); SequencePtr new_sequence = Core::instance()->CreateNewSequenceForProject(active_project.get());
new_sequence->set_default_parameters(); new_sequence->set_default_parameters();
+1 -1
View File
@@ -307,7 +307,7 @@ void MainMenu::TimecodeDisplayTriggered()
void MainMenu::FileMenuAboutToShow() void MainMenu::FileMenuAboutToShow()
{ {
Project* active_project = Core::instance()->GetActiveProject(); Project* active_project = Core::instance()->GetActiveProject().get();
file_project_properties_item_->setEnabled(active_project); file_project_properties_item_->setEnabled(active_project);
file_save_item_->setEnabled(active_project); file_save_item_->setEnabled(active_project);
+3 -3
View File
@@ -212,7 +212,7 @@ void MainWindow::SetTaskbarButtonProgress(int value, int max)
} }
#endif #endif
void MainWindow::FolderOpen(Project *p, Item *i, bool floating) void MainWindow::FolderOpen(Project* p, Item *i, bool floating)
{ {
ProjectPanel* panel = PanelManager::instance()->CreatePanel<ProjectPanel>(this); ProjectPanel* panel = PanelManager::instance()->CreatePanel<ProjectPanel>(this);
@@ -287,7 +287,7 @@ void MainWindow::ToggleMaximizedPanel()
} }
} }
void MainWindow::ProjectOpen(Project* p) void MainWindow::ProjectOpen(Project *p)
{ {
// See if this project is already open, and switch to it if so // See if this project is already open, and switch to it if so
foreach (ProjectPanel* pl, project_panels_) { foreach (ProjectPanel* pl, project_panels_) {
@@ -397,7 +397,7 @@ void MainWindow::ProjectCloseRequested()
ProjectPanel* panel = static_cast<ProjectPanel*>(sender()); ProjectPanel* panel = static_cast<ProjectPanel*>(sender());
Project* p = panel->project(); Project* p = panel->project();
Core::instance()->CloseProject(p, true); Core::instance()->CloseProject(Core::instance()->GetSharedPtrFromProject(p), true);
} }
void MainWindow::FolderCloseRequested() void MainWindow::FolderCloseRequested()