Undo Confusion

I need some help with an undo situation. I’m building a specialized text editor and I have buttons in a toolbar for all edit menu functions. Text is in a TextArea and text is styled using a syntax highlighting routine. I found that the OS seems to handle the undo needs just fine, so I didn’t add a menu handler for that. With no menu handler, my app seems to not have a connection to the undo menu item in the edit menu. Testing for enabled or disabled didn’t work and also checked for text changes, but that also didn’t work. Adding a menu handler for it and, even when returning false seems to turn off the internal undo system.

I’m not unfamiliar with creating an undo class to handle this all on my own, but everything I need is already done for me, and grouping multiple key downs into a single undo is a pain. How do I get the true status of the undo menu without a menu handler?

Second undo issue…

My app has a list of documents next to the Textarea. Clicking on a document name in the list opens the document in the Textarea. If a previous document had changes, the undo menu is active. Selecting a new document and loading into the text area allows the previous documents undo in the new document. How do I clear the internal undo when switching to a new document?

The first issue could be handled by registering for notifications with the NSUndoManager for Mac (sorry, I don’t have example code). Not sure about win32/linux The second could be handled with NSUndoManager declares (removeAllActionsWithTarget:), or by using a control array and creating a new textarea before you populate the text (but that seems like a major hack…)

It sounds like you’re running into some of the issues that prompted me to write TheBigUndo… it’s a commercial solution that I offer that would make this easy to handle.

Nothing like NSUndoManager in Win32.

A quick google reveals a way to clear the undo buffer

#if TargetWin32 Declare Function SendMessageA Lib "User32" Alias "SendMessageA" (hwnd As Integer, wMsg As Integer, wParam As Integer, lParam As Integer) As Integer Declare Function SendMessageW Lib "User32" Alias "SendMessageW" (hwnd As Integer, wMsg As Integer, wParam As Integer, lParam As Integer) As Integer // EM_EMPTYUNDOBUFFER = &hCD If System.IsFunctionAvailable( "SendMessageW", "User32" ) Then Call SendMessageW(Self.Handle, &hCD, 0, 0) Else Call SendMessageA(Self.Handle, &hCD, 0, 0) End If #endif

from http://forums.realsoftware.com/viewtopic.php?f=6&t=42790

Thanks Jim,

I should have specified that I needed an OSX only, but it’s nice to see I have some options if I decide to compile for Windows.

It looks like NSUndoManager is the direction I need to go… Thank you for that info.

I haven’t looked at this at all yet, but I have a question. I’m using a Textarea which is an NSTextView. I think the undo manager is already bound to the NSTextView. No? I’m guessing I need to look how to access the undo manager through the NSTextView. I have some reading to do. I think the last time I broached this, it prompted me to write my own undo class (for custom objects only). This time I need learn how to do this.

I may be back after bumping into all four walls…

I believe the undo manager is assigned to the window and manages undos for all of the undoable controls unless Xojo uses their own subclass and assigns one to each control (this I do not know), safest bet is to get the manager directly from the view in question… In any case, you can get a reference from the contentView, but the target is the textStorage object… I couldn’t help putting a snippet together.

This will clear undos for textarea1:

[code] Declare Function undoManager lib “Cocoa” selector “undoManager” (obj_ref as ptr) as ptr
Declare Sub removeAllActionsWithTarget lib “Cocoa” selector “removeAllActionsWithTarget:” (obj_ref as ptr,target as Ptr)
Declare Function documentView lib “Cocoa” selector “documentView” (obj_ref as ptr) as Ptr
Declare Function textStorage lib “Cocoa” selector “textStorage” (obj_ref as ptr) as Ptr

dim docView As ptr=documentView(ptr(TextArea1.Handle))
dim textStor As ptr=textStorage(docView)
dim undoMgr as ptr=undoManager(docview)
removeAllActionsWithTarget(undoMgr,textStor)[/code]

Thanks again Jim,

I now have things working as I need. I haven’t done any extensive testing yet, but I think I’m good with what I have. I refactored the solution down to 3 one line pieces of code and placed each in an appropriate event. I was able to get a reference of the undo manage for the NSTextView. I now also have the option of adding a redo edit function as well.

I don’t see how to mark this post as solved, is there one?

Now on the the next issue…

Here is the undo function for Windows :

Sub Action() #if TargetWin32 Declare Function SendMessageA Lib "User32" Alias "SendMessageA" (hwnd As Integer, wMsg As Integer, wParam As Integer, lParam As Integer) As Integer Declare Function SendMessageW Lib "User32" Alias "SendMessageW" (hwnd As Integer, wMsg As Integer, wParam As Integer, lParam As Integer) As Integer // EM_EMPTYUNDOBUFFER = &hCD const EM_UNDO = 199 If System.IsFunctionAvailable( "SendMessageW", "User32" ) Then Call SendMessageW(TextArea1.Handle, EM_UNDO, 0, 0) Else Call SendMessageA(TextArea1.Handle, EM_UNDO, 0, 0) End If #endif End Sub