NSUndoManager: disable "redo" for destructive action - objective-c

I'd like to add undo/redo functionality to my Mac app. The app works with notes and I'd like to add an "undo" action for when the user deletes a note.
This works just fine, the "Undo Delete Note" menu becomes active after the user deleted a note, but after using the "Undo Delete Note" command, there is a "Redo Delete Note" menu that becomes active.
Currently nothing happens when I click "Redo Delete Note", because I didn't register an action. I don't want the user to be able to delete a note accidentally through the undo/redo stack.
Is it possible to add an "undo" action without a "redo" action?

Not in the common case. And to do so would be to violate the implicit contract of the platform-standard undo/redo mechanism. You want the things you register to be symmetric. If a user deletes a note, then the available undo action should bring the note back. If the user elects to undo, then the redo action would be to "delete the note" again. It shouldn't matter if a user "accidentally" deletes a note by virtue of undo or redo, because they should always be able to get it back by doing the inverse action, right?
Don't overthink this.

Related

How do I prevent the user moving to a new record with dirty data?

If I'm creating a new record, and have logic that fires when the user presses the save button. This creates a problem that the user can create a new record, but not press the 'save' button, but just navigate to a new/previous record. The data will be saved, but the other VBA logic won't be fired.
I wish to prevent this, so which would be the best way? I would like navigation to be allowed on the form, just not when the record is new and dirty (navigation during updates are fine).
I've thought of two ideas, but am not sure how to implement either, nor which would be more logical. How would I do these:
Idea 1: Disable the navigation when a record is new and is dirty
Idea 2: Fire the 'presave' logic when the user navigates away from a dirty new record.
You can add your 'logic' in the Form Event "After update"
Private Sub Form_AfterUpdate()
'do some logic stuff here or call another method
End Sub
When I tried it, Access was able to distinguish correctly if the form is dirty or not before firing this event. But you should try it on your own.

NSDocument isDocumentEdited and undo

In a document-based application, for every user action I add an entry in the UndoManager, including selection, meaning that an 'undo' will restore the previous selection.
Some times a user will open a document, view some items by selecting them and then close the document, but even if the user didn't 'alter' anything, the user is asked to save changes, this is annoying and can be misleading to the user.
It seems that the document's dirty flag (isDocumentEdited) is automatically set when registering undo actions, but is there a way I can prevent this for some particualr undoable actions, such as selection change?
Thanks!
You should be able to call -setActionIsDiscardable:YES on the undoManager when you register actions that don’t need to be saved.

Silverlight avoid requesting an event twice

I have a Control say for ex a Submit button if user clicks the button twice or more continuously then user receiving same message / same operation taking place twice or more.
I need to avoid this situation.
thanks for your inputs.
You need to detect the button click event either in the code behind of the view (or ViewModel if using the MVVM pattern) and disable the button. Now I take it that your submit button is firing off some kind of asynchronous operation. Once the asynchronous operation has successfully completed you will probably need to enable the button so that it is available again.
Shankar, if you want to avoid clicking on button, you should disable it. If you can give more details about what exactly you are trying to do, more details can be given.

How can I make a button not fire its action on click-through?

The Apple Human Interface Guidelines state that:
An item that provides click-through is one that a user can activate on an inactive window with one click, instead of clicking first to make the window active and then clicking the item. Click-through provides greater efficiency in performing such tasks as closing or resizing inactive windows, and copying or moving files. In many cases, however, click-through could confuse a user who clicks an item unintentionally.
and
Don’t provide click-through for an item or action that:
Is potentially harmful and does not allow the user to cancel it (for example, the Delete button in Mail)
Is difficult or impossible to cancel (such as the Send button in Mail)
Dismisses a dialog without telling the user what action was taken (for example, the Save button in a Save dialog that overwrites an existing file and automatically dismisses the dialog)
Removes the user from the current context (for example, selecting a new item in a Finder column can change the target of the Finder window)
What I want to do is that if the user clicks a specific button it will not send its message unless the window is active (for example, the delete message button in Mail). How can I achieve this? If I need to subclass NSButton that's fine.
Look at the NSView Documentation:
http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ApplicationKit/Classes/NSView_Class/Reference/NSView.html#//apple_ref/occ/instm/NSView/acceptsFirstMouse:
You need to override acceptsFirstMouse to return TRUE to enable click through.
The default behaviour is not click-through:
The default implementation ignores theEvent and returns NO.
It's possible you have already overridden this method in your code, or in code you have based your code on. Try removing the implementation of acceptsFirstMouse in your code.

How can I "undo send" like in Gmail?

How can I undo send, save or delete in Vb like Gmail is using this feature in Messages.
The feature used by Gmail is they are queing the message for 5 secs and if the user clicks on Undo before that 5secs the whole send process is pulled back.
Now what I want is to implement this same in my Vb.net application. Is there any code available to do this. Please help ?
About an "undo send" feature, the most evident way of doing that is to actually not "do" what you want to "undo".
What I mean is :
When a user clicks on "send", you should not really send the message
Instead, you should mark it as "to send in X seconds" -- place it in some queue, for instance
Which means it'll only be sent after X seconds, and not immediatly.
During this X number of seconds, if the user clicks "undo send", you just have to remove that mail from the "waiting queue"
Of course, you cannot "undo send" on a mail which has already been sent : it's gone from your server, and there is nothing you can do anymore about it.
To implement that, you'll need :
Some queue for actions
To place your data into this queue when the user clicks "send"
To have some batch that really sends data that's been in the queue for more than X seconds
To remove the data from the queue when the user clicks "undo send".
The same idea can be applied to "undo delete" :
When a user clicks on "delete", don't physicilly delete the data
Instead, use some boolean flag to indicate that it should be considered as deleted
Then, un-doping that deletion only means de-activating that flag
This can easily be implemented in any language :
Add a is_deleted field on your data
When displaying the data, filter those for which this flag is enabled
When deleting, instead of physically deleting, set this flag
When un-deleting, un-set this flag
The "undo save" can be a bit harder : a solution would be to not keep only one version of the message, but several :
Each time the user clicks "save", you should store a new version of the message
Which means you'll end up, after some time, with many versions of the message
Which will allow you to "come back" to a previous version, restoring it from the history.
This can be done :
adding a new field called like "version" on your data.
each time the user saves, just increment that field, and store a copy of the data
i.e. never actually update any exiting data, but always insert a new version of it.
then, "undo save" only means "get the previous version of the data"