Community Tip - Stay updated on what is happening on the PTC Community by subscribing to PTC Community Announcements. X
Unforunatley, I'm finding it not so simple.
I can tell if a user has made changes by testing modified(), but we have a small group of users getting signal 11 crashes.
We send things back to our CMS using a destroy callback, which calls a program that sends the changes to our server and unlocks the material, and I need to know if a user has seen the "Save changed file" dialog since I can't predict the state of things during these crashes. We're working to eliminate the cause of the crash, and our original assumption was that Arbortext would just stop, leaving our last set of files around so we could recover them manually. Unfortunately, that doesn't seem to bethe case. The destroy callback is called AFTER the crash, so I'd like to have it do nothing IF the "save changed" popup never appeared, or if it did just before the crash and the authorselected "No".
I'm in a situation where I can't reproduce the crash myself, so I want to add a few more safety tests to the code.
Our users are using 5.3 M090. I'm sure we can troubleshoot the crashing eventually, but even so, I think I need to rework how we've saving the documents.
We have a global variable indicating a saved document that's intialized to 0, and we only set it to 1 when somone actively saves the document. Our process that stores things back to the server also cleans up all the work files, and this came up when we realized that after the crash, we have no autosave file (we have a support call to PTC about why we can't consistently get autosave files to exist), and since the author hadn't saved yet, our "save" flag is set to 0 so our post-process assumed no changes and just removed all the files.
I think we need to reverse that logic, initializing our "save" flag to true, and only setting it to false when a user responds with a "no" to the "Save changes" prompt. That's why I'm hoping to somehow capture that response, and so far, the only way I know to do that is to remap all commands that might trigger it to my own function. We could probably make that work, but I was hoping there was a piece of ACL code behind that dialog that we could customize and thereby save the choice into a global variable that I could examine in the destroy callback.
My only other choice is to have the program that takes control afterwards look at breadcrumbs on the system, and I'd rather find a way to have Arbortext reliably inform the next process of what happened. Users might make changes in a file that they have no intention of saving, and in particular, if a user never got to the point where the editor asked them to save but we see that the document was modified, I want to err on the side of caution rather than do what we're doing now, assuming that the user didn't want to save the changes.
Thanks Brandon. You're describing the code pretty much the way it is now, and it's worked until we started experiencing crashes.
Yes, I want to store changes if a user did at least one save, even if they abort changes made since a prior save when closing the file. Using the save callback is doing that just fine.
But consider this scenario:
1. SAVE global is initialized to 0
2. User edits the document, and Arbortext crashes.
3. The destroy callback acts on the saved value of 0, assuming the user has aborted the changes. In reality, they've never had the chance to save before the crash, and our code assumes changes were aborted, unlocks the files on our CMS and discards the files on the Windows workstation. The work done is lost.
I think I need more than an "off" and "on" in our save variable and a few more smarts in the save callback.
Something like:
1. SAVE global is initialized to -1, indicating the user has done neither a save nor a discard of changes.
2. If a user is presented with a SAVE option (no matter what the method):
If the response is "Yes", reset SAVE to 1.
If the response is "No", and save is currently -1, reset it to 0,
In Reply to Brandon Ibach:
Steven,
Correct me if I'm wrong, but your global variable is tracking whether the user has written a modified version of the document to disk, such that it needs to be sent to the repository, rather than just unlocked and discarded.
If this is correct, then again, I think what you really want to track in your global variable is whether the document was actually written to disk at any point, whether by an explicit "Save" request by the user (via menu, shortcut key, toolbar button, or whatever), via a "Yes" answer to the "Save changes?" dialog, or any other mechanism. Why you'd want to reset the variable to "false" just because the user says "No" to saving changes, particularly if they've explicitly saved the document one or more times prior to this, I don't see.
Unless I'm not understanding some detail, then (if so, I apologize... please correct me), then what you want to do is register a function with the "save" callback, which will call your function any time a document is to be saved, regardless of how the save was initiated. Try a simple example that throws up a message box and I think you'll find that it allows you to insert your custom code at just the right point.
-Brandon 🙂
Thanks Brandon. You're describing the code pretty much the way it is now, and it's worked until we started experiencing crashes.
Yes, I want to store changes if a user did at least one save, even if they abort changes made since a prior save when closing the file. Using the save callback is doing that just fine.
But consider this scenario:
1. SAVE global is initialized to 0
2. User edits the document, and Arbortext crashes.
3. The destroy callback acts on the saved value of 0, assuming the user has aborted the changes. In reality, they've never had the chance to save before the crash, and our code assumes changes were aborted, unlocks the files on our CMS and discards the files on the Windows workstation. The work done is lost.
I think I need more than an "off" and "on" in our save variable and a few more smarts in the save callback.
Something like:
1. SAVE global is initialized to -1, indicating the user has done neither a save nor a discard of changes.
2. If a user is presented with a SAVE option (no matter what the method):
If the response is "Yes", reset SAVE to 1.
If the response is "No", and save is currently -1, reset it to 0,
In Reply to Brandon Ibach:
Steven,
Correct me if I'm wrong, but your global variable is tracking whether the user has written a modified version of the document to disk, such that it needs to be sent to the repository, rather than just unlocked and discarded.
If this is correct, then again, I think what you really want to track in your global variable is whether the document was actually written to disk at any point, whether by an explicit "Save" request by the user (via menu, shortcut key, toolbar button, or whatever), via a "Yes" answer to the "Save changes?" dialog, or any other mechanism. Why you'd want to reset the variable to "false" just because the user says "No" to saving changes, particularly if they've explicitly saved the document one or more times prior to this, I don't see.
Unless I'm not understanding some detail, then (if so, I apologize... please correct me), then what you want to do is register a function with the "save" callback, which will call your function any time a document is to be saved, regardless of how the save was initiated. Try a simple example that throws up a message box and I think you'll find that it allows you to insert your custom code at just the right point.
-Brandon 🙂
Thanks Brandon. That's pretty much what we're doing, but we've encounted a flaw in the logic in the event of a crash.
Consider this scenario:
1)
In Reply to Brandon Ibach:
Steven,
Correct me if I'm wrong, but your global variable is tracking whether the user has written a modified version of the document to disk, such that it needs to be sent to the repository, rather than just unlocked and discarded.
If this is correct, then again, I think what you really want to track in your global variable is whether the document was actually written to disk at any point, whether by an explicit "Save" request by the user (via menu, shortcut key, toolbar button, or whatever), via a "Yes" answer to the "Save changes?" dialog, or any other mechanism. Why you'd want to reset the variable to "false" just because the user says "No" to saving changes, particularly if they've explicitly saved the document one or more times prior to this, I don't see.
Unless I'm not understanding some detail, then (if so, I apologize... please correct me), then what you want to do is register a function with the "save" callback, which will call your function any time a document is to be saved, regardless of how the save was initiated. Try a simple example that throws up a message box and I think you'll find that it allows you to insert your custom code at just the right point.
-Brandon 🙂
Sorry for the incomplete answer. My instinct to hit TAB keeps sending an incomplete message! I'll try one more time:
Thanks Brandon. You're describing the code pretty much the way it is now, and it's worked until we started experiencing crashes.
Yes, I want to store changes if a user did at least one save, even if they abort changes made since a prior save when closing the file. Using the save callback is doing that just fine.
But consider this scenario:
1. SAVE global is initialized to 0
2. User edits the document, and Arbortext crashes.
3. The destroy callback acts on the saved value of 0, assuming the user has aborted the changes. In reality, they've never had the chance to save before the crash, and our code assumes changes were aborted, unlocks the files on our CMS and discards the files on the Windows workstation. The work done is lost.
I think I need more than an "off" and "on" in our save variable and a few more smarts in the save callback.
Something like:
1. SAVE global is initialized to -1, indicating the user has done neither a save nor a discard of changes.
2. If a user is presented with a SAVE option (no matter what the method):
If the response is "Yes", reset SAVE to 1.
If the response is "No", and save is currently 1, leave it at 1, but don't save again, indicating a save has already happened and that file should be uploaded.
If the response is "No", and save is any other #, set SAVE to 0
3. In the "destroy" callback, we now have 3 things to test for:
a) If SAVE = 1, upload the changed file;
b) If SAVE = 0, changes were explicitly discarded. Unlock material on the server and delete the files;
c) If SAVE = -1, the user hasn't had a chance to save or discard changes, something wrong happened. Leave the material locked on the server and don't delete the work files so work can be recovered by someone on our support staff.
To do this, I need to know not just when the file was saved, but what response the user gave to the save dialog. If there's another approach I'm not considering that would cover the crashed editor scenario that I can use, I'll give it a try.
I don't yet see any way to capture the response to the save, other than writing our own and mapping it to all of the possible combinations that could trigger it. I was hoping to avoid that and just capture the information that Arbortext seems to know about somewhere anyway.
Thanks again!
In Reply to Steven Haber:
Thanks Brandon. You're describing the code pretty much the way it is now, and it's worked until we started experiencing crashes.
Yes, I want to store changes if a user did at least one save, even if they abort changes made since a prior save when closing the file. Using the save callback is doing that just fine.
But consider this scenario:
1. SAVE global is initialized to 0
2. User edits the document, and Arbortext crashes.
3. The destroy callback acts on the saved value of 0, assuming the user has aborted the changes. In reality, they've never had the chance to save before the crash, and our code assumes changes were aborted, unlocks the files on our CMS and discards the files on the Windows workstation. The work done is lost.
I think I need more than an "off" and "on" in our save variable and a few more smarts in the save callback.
Something like:
1. SAVE global is initialized to -1, indicating the user has done neither a save nor a discard of changes.
2. If a user is presented with a SAVE option (no matter what the method):
If the response is "Yes", reset SAVE to 1.
If the response is "No", and save is currently -1, reset it to 0,
In Reply to Brandon Ibach:Steven,
Correct me if I'm wrong, but your global variable is tracking whether the user has written a modified version of the document to disk, such that it needs to be sent to the repository, rather than just unlocked and discarded.
If this is correct, then again, I think what you really want to track in your global variable is whether the document was actually written to disk at any point, whether by an explicit "Save" request by the user (via menu, shortcut key, toolbar button, or whatever), via a "Yes" answer to the "Save changes?" dialog, or any other mechanism. Why you'd want to reset the variable to "false" just because the user says "No" to saving changes, particularly if they've explicitly saved the document one or more times prior to this, I don't see.
Unless I'm not understanding some detail, then (if so, I apologize... please correct me), then what you want to do is register a function with the "save" callback, which will call your function any time a document is to be saved, regardless of how the save was initiated. Try a simple example that throws up a message box and I think you'll find that it allows you to insert your custom code at just the right point.
-Brandon 🙂
I think I've got a working solution, thanks to all for their assistance.
Since I want to capture my state not just when windows close, but even if a user does an interim save, I ended up doing what I was trying to avoid, but it wasn't too difficult.
I'm mapping all save menu items and keystrokes to a function that does what I need, and mapping any menu item and keystroke that attempts to quit the editor to another one that also checks to see if the content was modified and then calls my custom save function.
My save function brings up its own response dialog prompting a user if they want to save changes that looks identical to the Arbortext one, but it handles setting my flags, and then I'm testing them in the destroy callback. If I see the initial state, I know something went wrong and I can inform the user and stop the CMS process from cleaning up. It seems to be working, I've passed the code onto my colleage who manages our ACL, and she'll be testing it with a "real" user who is still experiencing crashes sometime today.
Thanks, all!
In Reply to Brandon Ibach:
Ah, now this is clearer. 🙂
I'm not sure if there's a good way to capture the appearance or the result of the "save changes?" dialog, but it seems like you really just need to know when to set your flag from the "initial/unknown" state (-1) to the "no save" state (0). Rather than triggering this transition on a "No" response from the user, why not do it at the point when the dialog is about to appear? If the user says "No", then the state will already be 0, nothing will change and you're covered. If they answer "Yes", your "save" callback should set the state to 1.
Unfortunately, the order of callbacks seems to vary somewhat depending on the method by which a document close is initiated. From a quick experiment, I see that the window quit callback fires twice (once each with op=1 and op=2) just before the "save changes?" dialog after a file close, but not until after that dialog on an application close. However, on application close, the session quit callback fires before the dialog. So, handling both of these callbacks should give you the notification you need to handle either of these two cases. As far as other shutdown scenarios, such as the crashes you're experiencing, I can't say what the sequence might be, so you'll need to experiment.
Hope this helps...
-Brandon 🙂