core: implemented yes/no to all when closing multiple modified projects
This commit is contained in:
+122
-39
@@ -274,6 +274,17 @@ const QStringList &Core::GetRecentProjects() const
|
||||
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)
|
||||
{
|
||||
tool_ = tool;
|
||||
@@ -328,7 +339,7 @@ void Core::DialogPreferencesShow()
|
||||
|
||||
void Core::DialogProjectPropertiesShow()
|
||||
{
|
||||
ProjectPropertiesDialog ppd(GetActiveProject(), main_window_);
|
||||
ProjectPropertiesDialog ppd(GetActiveProject().get(), main_window_);
|
||||
ppd.exec();
|
||||
}
|
||||
|
||||
@@ -357,7 +368,7 @@ void Core::CreateNewFolder()
|
||||
|
||||
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
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -383,15 +394,15 @@ void Core::CreateNewFolder()
|
||||
|
||||
void Core::CreateNewSequence()
|
||||
{
|
||||
Project* active_project = GetActiveProject();
|
||||
ProjectPtr active_project = GetActiveProject();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// Create new sequence
|
||||
SequencePtr new_sequence = CreateNewSequenceForProject(active_project);
|
||||
SequencePtr new_sequence = CreateNewSequenceForProject(active_project.get());
|
||||
|
||||
// Set all defaults for the sequence
|
||||
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 (!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);
|
||||
@@ -496,6 +507,7 @@ void Core::DeclareTypesForQt()
|
||||
qRegisterMetaType<Decoder::RetrieveState>();
|
||||
qRegisterMetaType<TimeRange>();
|
||||
qRegisterMetaType<Color>();
|
||||
qRegisterMetaType<ProjectPtr>();
|
||||
}
|
||||
|
||||
void Core::StartGUI(bool full_screen)
|
||||
@@ -545,7 +557,7 @@ void Core::StartGUI(bool full_screen)
|
||||
autorecovery_timer_.start();
|
||||
}
|
||||
|
||||
void Core::SaveProjectInternal(Project *project)
|
||||
void Core::SaveProjectInternal(ProjectPtr project)
|
||||
{
|
||||
// Create save manager
|
||||
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());
|
||||
|
||||
p->set_modified(false);
|
||||
}
|
||||
|
||||
Project *Core::GetActiveProject() const
|
||||
ProjectPtr Core::GetActiveProject() const
|
||||
{
|
||||
ProjectPanel* active_project_panel = PanelManager::instance()->MostRecentlyFocused<ProjectPanel>();
|
||||
|
||||
if (active_project_panel) {
|
||||
return active_project_panel->project();
|
||||
} else {
|
||||
return nullptr;
|
||||
if (active_project_panel && active_project_panel->project()) {
|
||||
return GetSharedPtrFromProject(active_project_panel->project());
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ProjectViewModel *Core::GetActiveProjectModel() const
|
||||
@@ -636,7 +648,7 @@ QString Core::PasteStringFromClipboard()
|
||||
|
||||
bool Core::SaveActiveProject()
|
||||
{
|
||||
Project* active_project = GetActiveProject();
|
||||
ProjectPtr active_project = GetActiveProject();
|
||||
|
||||
if (active_project) {
|
||||
return SaveProject(active_project);
|
||||
@@ -647,7 +659,7 @@ bool Core::SaveActiveProject()
|
||||
|
||||
bool Core::SaveActiveProjectAs()
|
||||
{
|
||||
Project* active_project = GetActiveProject();
|
||||
ProjectPtr active_project = GetActiveProject();
|
||||
|
||||
if (active_project) {
|
||||
return SaveProjectAs(active_project);
|
||||
@@ -659,7 +671,7 @@ bool Core::SaveActiveProjectAs()
|
||||
bool Core::SaveAllProjects()
|
||||
{
|
||||
foreach (ProjectPtr p, open_projects_) {
|
||||
if (!SaveProject(p.get())) {
|
||||
if (!SaveProject(p)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -674,12 +686,12 @@ bool Core::CloseActiveProject()
|
||||
|
||||
bool Core::CloseAllExceptActiveProject()
|
||||
{
|
||||
Project* active_proj = GetActiveProject();
|
||||
ProjectPtr active_proj = GetActiveProject();
|
||||
QList<ProjectPtr> copy = open_projects_;
|
||||
|
||||
foreach (ProjectPtr p, copy) {
|
||||
if (p.get() != active_proj) {
|
||||
if (!CloseProject(p.get(), true)) {
|
||||
if (p != active_proj) {
|
||||
if (!CloseProject(p, true)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -774,7 +786,7 @@ QString Core::GetRecentProjectsFilePath()
|
||||
return QDir(GetConfigurationLocation()).filePath(QStringLiteral("recent"));
|
||||
}
|
||||
|
||||
bool Core::SaveProject(Project *p)
|
||||
bool Core::SaveProject(ProjectPtr p)
|
||||
{
|
||||
if (p->filename().isEmpty()) {
|
||||
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_,
|
||||
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++) {
|
||||
if (open_projects_.at(i).get() == p) {
|
||||
if (open_projects_.at(i) == p) {
|
||||
|
||||
if (p->is_modified()) {
|
||||
QMessageBox mb(main_window_);
|
||||
if (p->is_modified() && confirm_behavior != kCloseProjectDontSave) {
|
||||
|
||||
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()));
|
||||
bool save_this_project;
|
||||
|
||||
QPushButton* yes_btn = mb.addButton(tr("Save"), QMessageBox::YesRole);
|
||||
mb.addButton(tr("Don't Save"), QMessageBox::NoRole);
|
||||
QPushButton* cancel_btn = mb.addButton(QMessageBox::Cancel);
|
||||
if (confirm_behavior == kCloseProjectAsk || confirm_behavior == kCloseProjectOnlyOne) {
|
||||
QMessageBox mb(main_window_);
|
||||
|
||||
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
|
||||
|| (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_btn = mb.addButton(tr("Save"), QMessageBox::YesRole);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
disconnect(p, &Project::ModifiedChanged, this, &Core::ProjectWasModified);
|
||||
emit ProjectClosed(p);
|
||||
// For safety, the undo stack is cleared so no commands try to affect a freed project
|
||||
undo_stack_.clear();
|
||||
|
||||
disconnect(p.get(), &Project::ModifiedChanged, this, &Core::ProjectWasModified);
|
||||
emit ProjectClosed(p.get());
|
||||
open_projects_.removeAt(i);
|
||||
break;
|
||||
}
|
||||
@@ -953,10 +1012,34 @@ bool Core::CloseAllProjects(bool auto_open_new)
|
||||
{
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
|
||||
modified_count--;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
+19
-6
@@ -124,6 +124,11 @@ public:
|
||||
*/
|
||||
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
|
||||
*
|
||||
@@ -134,7 +139,7 @@ public:
|
||||
*
|
||||
* The active Project file, or nullptr if the heuristic couldn't find one.
|
||||
*/
|
||||
Project* GetActiveProject() const;
|
||||
ProjectPtr GetActiveProject() const;
|
||||
ProjectViewModel* GetActiveProjectModel() const;
|
||||
Folder* GetSelectedFolderInActiveProject() const;
|
||||
|
||||
@@ -206,10 +211,18 @@ public:
|
||||
*/
|
||||
void OpenProjectFromRecentList(int index);
|
||||
|
||||
enum CloseProjectBehavior {
|
||||
kCloseProjectOnlyOne,
|
||||
kCloseProjectAsk,
|
||||
kCloseProjectSave,
|
||||
kCloseProjectDontSave
|
||||
};
|
||||
|
||||
/**
|
||||
* @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
|
||||
@@ -365,12 +378,12 @@ private:
|
||||
/**
|
||||
* @brief Saves a specific project
|
||||
*/
|
||||
bool SaveProject(Project* p);
|
||||
bool SaveProject(ProjectPtr p);
|
||||
|
||||
/**
|
||||
* @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)
|
||||
@@ -401,7 +414,7 @@ private:
|
||||
/**
|
||||
* @brief Internal function for saving a project to a file
|
||||
*/
|
||||
void SaveProjectInternal(Project* project);
|
||||
void SaveProjectInternal(ProjectPtr project);
|
||||
|
||||
/**
|
||||
* @brief Internal main window object
|
||||
@@ -459,7 +472,7 @@ private:
|
||||
private slots:
|
||||
void SaveAutorecovery();
|
||||
|
||||
void ProjectSaveSucceeded(Project *p);
|
||||
void ProjectSaveSucceeded(ProjectPtr p);
|
||||
|
||||
/**
|
||||
* @brief Adds a project to the "open projects" list
|
||||
|
||||
@@ -69,12 +69,12 @@ ProjectPanel::ProjectPanel(QWidget *parent) :
|
||||
Retranslate();
|
||||
}
|
||||
|
||||
Project *ProjectPanel::project() const
|
||||
Project* ProjectPanel::project() const
|
||||
{
|
||||
return explorer_->project();
|
||||
}
|
||||
|
||||
void ProjectPanel::set_project(Project *p)
|
||||
void ProjectPanel::set_project(Project* p)
|
||||
{
|
||||
if (project()) {
|
||||
disconnect(project(), &Project::NameChanged, this, &ProjectPanel::UpdateSubtitle);
|
||||
@@ -92,6 +92,8 @@ void ProjectPanel::set_project(Project *p)
|
||||
|
||||
UpdateSubtitle();
|
||||
|
||||
emit ProjectNameChanged();
|
||||
|
||||
if (p) {
|
||||
setWindowModified(p->is_modified());
|
||||
} else {
|
||||
|
||||
@@ -82,4 +82,6 @@ private slots:
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
|
||||
Q_DECLARE_METATYPE(OLIVE_NAMESPACE::ProjectPtr)
|
||||
|
||||
#endif // PROJECT_PANEL_H
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
|
||||
ProjectSaveManager::ProjectSaveManager(Project *project) :
|
||||
ProjectSaveManager::ProjectSaveManager(ProjectPtr project) :
|
||||
project_(project)
|
||||
{
|
||||
SetTitle(tr("Saving '%1'").arg(project->filename()));
|
||||
|
||||
@@ -30,16 +30,16 @@ class ProjectSaveManager : public Task
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
ProjectSaveManager(Project* project);
|
||||
ProjectSaveManager(ProjectPtr project);
|
||||
|
||||
signals:
|
||||
void ProjectSaveSucceeded(Project* p);
|
||||
void ProjectSaveSucceeded(ProjectPtr p);
|
||||
|
||||
protected:
|
||||
virtual void Action() override;
|
||||
|
||||
private:
|
||||
Project* project_;
|
||||
ProjectPtr project_;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -321,10 +321,10 @@ void TimelineWidget::ImportTool::DropGhosts(bool insert)
|
||||
}
|
||||
|
||||
if (behavior != kDWSDisable) {
|
||||
Project* active_project = Core::instance()->GetActiveProject();
|
||||
ProjectPtr active_project = Core::instance()->GetActiveProject();
|
||||
|
||||
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();
|
||||
|
||||
|
||||
@@ -307,7 +307,7 @@ void MainMenu::TimecodeDisplayTriggered()
|
||||
|
||||
void MainMenu::FileMenuAboutToShow()
|
||||
{
|
||||
Project* active_project = Core::instance()->GetActiveProject();
|
||||
Project* active_project = Core::instance()->GetActiveProject().get();
|
||||
|
||||
file_project_properties_item_->setEnabled(active_project);
|
||||
file_save_item_->setEnabled(active_project);
|
||||
|
||||
@@ -212,7 +212,7 @@ void MainWindow::SetTaskbarButtonProgress(int value, int max)
|
||||
}
|
||||
#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);
|
||||
|
||||
@@ -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
|
||||
foreach (ProjectPanel* pl, project_panels_) {
|
||||
@@ -397,7 +397,7 @@ void MainWindow::ProjectCloseRequested()
|
||||
ProjectPanel* panel = static_cast<ProjectPanel*>(sender());
|
||||
Project* p = panel->project();
|
||||
|
||||
Core::instance()->CloseProject(p, true);
|
||||
Core::instance()->CloseProject(Core::instance()->GetSharedPtrFromProject(p), true);
|
||||
}
|
||||
|
||||
void MainWindow::FolderCloseRequested()
|
||||
|
||||
Reference in New Issue
Block a user