Skip to content

Commit

Permalink
[SHOT-3502] Prompt save changes on opening new file (#44)
Browse files Browse the repository at this point in the history
* Add method to engine to check for unsaved changes by checking window title for '*' (no VRED API for this).
* Modify the workfiles reset scene operation hook to check for unsaved changes, and propmt the user to save or discard changes before continuing.
* Use the Workfiles2 File Save dialog when calling VRED engine to save a file, fallback to VRED's save dialog if Workfiles2 is not set up
  • Loading branch information
staceyoue authored Oct 7, 2020
1 parent 64b5a96 commit 7a54cfa
Show file tree
Hide file tree
Showing 2 changed files with 100 additions and 17 deletions.
62 changes: 50 additions & 12 deletions engine.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
# -*- coding: utf-8 -*-

# Copyright (c) 2015 Shotgun Software Inc.
# Copyright (c) 2020 Autodesk Inc.
# CONFIDENTIAL AND PROPRIETARY
#
# This work is provided "AS IS" and subject to the Shotgun Pipeline Toolkit
# Source Code License included in this distribution package. See LICENSE.
# By accessing, using, copying or modifying this work you indicate your
# agreement to the Shotgun Pipeline Toolkit Source Code License. All rights
# not expressly granted therein are reserved by Shotgun Software Inc.
# not expressly granted therein are reserved by Autodesk Inc.

import logging
import os
import re

import sgtk
from tank_vendor import six

import builtins

builtins.vrFileIOService = vrFileIOService
import vrController
import vrFileDialog
import vrFileIO
Expand Down Expand Up @@ -303,18 +307,44 @@ def show_panel(self, panel_id, title, bundle, widget_class, *args, **kwargs):
#####################################################################################
# VRED File IO

def has_unsaved_changes(self):
"""
Return True if the current scene has unsaved changes, otherwise False.
The VRED API does not currently have an endpoint to check for unsaved changes,
so to determine whether or not there are changes, check if the VRED window title
contains a '*' character (this indicates that there are changes in the scene).
"""

window_title_string = self._get_dialog_parent().windowTitle()
return re.findall(r"\*", window_title_string)

def open_save_as_dialog(self):
"""
Opens a file dialog and lets the user choose a filename and then save the supplied
project to that path.
Open the tk-multi-workfiles2 app's file save dialog. Fallback to using VRED save
dialog UI if workfiles is not available.
"""
path = vrFileDialog.getSaveFileName(
caption="Save As",
filename="",
filter=["VRED Project Binary (*.vpb)"],
)

if path:
open_dialog_func = None
kwargs = {}
workfiles = self.apps.get("tk-multi-workfiles2", None)

if workfiles:
if hasattr(workfiles, "show_file_save_dlg"):
open_dialog_func = workfiles.show_file_save_dlg
kwargs["use_modal_dialog"] = True

if open_dialog_func:
open_dialog_func(**kwargs)

else:
# Fallback to using VRED's save dialog. Pass flag to not confirm overwrite, the
# save dialog will already ask this.
path = vrFileDialog.getSaveFileName(
caption="Save As",
filename=vrFileIOService.getFileName(),
filter=["VRED Project Binary (*.vpb)"],
confirmOverwrite=False,
)
self.save_current_file(path, False)

def save_current_file(self, file_path, set_render_path=True):
Expand All @@ -324,6 +354,14 @@ def save_current_file(self, file_path, set_render_path=True):
:param file_path: the name of the project file.
"""

if not file_path:
self.logger.debug(
"{engine_name} no file path given for save -- aborting".format(
engine_name=self.name
)
)
return

self.logger.debug(
"{engine_name} calling VRED save for file '{path}'".format(
engine_name=self.name, path=file_path
Expand Down
55 changes: 50 additions & 5 deletions hooks/tk-multi-workfiles2/basic/scene_operation.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,14 @@
# Copyright (c) 2020 Autodesk, Inc.
# CONFIDENTIAL AND PROPRIETARY
#
# This work is provided "AS IS" and subject to the Shotgun Pipeline Toolkit
# Source Code License included in this distribution package. See LICENSE.
# By accessing, using, copying or modifying this work you indicate your
# agreement to the Shotgun Pipeline Toolkit Source Code License. All rights
# not expressly granted therein are reserved by Autodesk, Inc.

import sgtk
from sgtk.platform.qt import QtCore, QtGui

import vrController
import vrFileIO
Expand All @@ -9,7 +19,7 @@

class SceneOperation(HookClass):
"""
Hook called to perform an operation with the current file.
VRED scene operations for tk-multi-workfiles2
"""

def execute(
Expand Down Expand Up @@ -42,7 +52,7 @@ def execute(
:returns: Depends on operation:
'current_path' - Return the current scene file path as a String
all others - True
all others - True for success, else False
"""

self.logger.debug(
Expand All @@ -51,6 +61,8 @@ def execute(
)
)

success = True

if operation == "current_path":
current_path = vrFileIO.getFileIOFilePath()
return "" if current_path is None else current_path
Expand All @@ -74,6 +86,39 @@ def execute(
self.parent.engine.save_current_file(file_path)

elif operation == "reset":
vrController.newScene()

return True
# Do not let the user reset the scene until they have saved their changes,
# or explicitly said they do not want to save their changes. Override the
# cursor before opening any new dialogs, and restore once finished (the
# cursor is most likely to be "waiting" since we're in the reset operation).
restore_cursor = False
while self.parent.engine.has_unsaved_changes():
if not restore_cursor:
restore_cursor = True
QtGui.QApplication.setOverrideCursor(QtCore.Qt.ArrowCursor)

res = QtGui.QMessageBox.question(
None,
"Save your scene?",
"Your scene has unsaved changes. Save before proceeding?",
QtGui.QMessageBox.Yes
| QtGui.QMessageBox.No
| QtGui.QMessageBox.Cancel,
)

if res == QtGui.QMessageBox.Cancel:
success = False
break

if res == QtGui.QMessageBox.No:
break

# The user has indicated they want to save changes before proceeding
self.parent.engine.open_save_as_dialog()

if restore_cursor:
QtGui.QApplication.restoreOverrideCursor()

if success:
vrController.newScene()

return success

0 comments on commit 7a54cfa

Please sign in to comment.