{"id":229,"date":"2006-11-30T18:32:12","date_gmt":"2006-12-01T01:32:12","guid":{"rendered":"http:\/\/www.red-sweater.com\/blog\/229\/stay-responsive"},"modified":"2006-11-30T18:38:36","modified_gmt":"2006-12-01T01:38:36","slug":"stay-responsive","status":"publish","type":"post","link":"https:\/\/redsweater.com\/blog\/229\/stay-responsive","title":{"rendered":"Stay Responsive"},"content":{"rendered":"<p>In general, a user&#8217;s changes to a Cocoa NSTextField are saved when they finish editing (by tabbing or clicking to another field) or press return. This is fine, and it works 95% of the time. But on occasion we may find good reason to saved a user&#8217;s changes regardless of whether they&#8217;ve performed one of these completing actions.<\/p>\n<p>\nFor example, in the &#8220;Send to iTunes&#8221; feature I&#8217;m working on for FlexTime, I decided it was quite possible that a user would fine-tune an activity&#8217;s details, say change the text of a &#8220;Speak Text&#8221; cue, and then immediately select &#8220;Send to iTunes.&#8221; What should happen in this case? Certainly the user&#8217;s changes should be committed and included in the exported audio. The user hasn&#8217;t &#8220;finished editing&#8221; in a conventional way, but by choosing to export the routine, they&#8217;ve let me know they are expecting to hear what they&#8217;ve just typed.\n<\/p>\n<p>\nThe cleanest way to end editing for a particular window was explained to me a few years ago by Erik Buck, who kindly explained on a mailing list that it&#8217;s best to first ask the window to become firstResponder (thus taking firstReponder away from the focused field), and if that failed, to resort to the crude &#8220;endEditingFor:&#8221; method on NSWindow.\n<\/p>\n<p>\nThis works! But it has the side-effect of causing there to no longer <em>be<\/em> a reasonable first responder for the window. In the scenario I&#8217;m dealing with, I want to:\n<\/p>\n<ol>\n<li>Commit Edits.<\/li>\n<li>Send to iTunes.<\/li>\n<li>Put things back how they were.<\/li>\n<\/ol>\n<p>\nI figured if I could be responsible for taking first responder status away from some field in my window, I could just give it back after I was done. But things don&#8217;t work out so easily in a world where the mysterious field editor is always being injected into the view hierarchy.  My first naive solution resulted in my essentially saving and restoring the <em>field editor<\/em> as the first responder for the window. But after the editing has ended, the field editor isn&#8217;t even on the screen anymore. So setting it to first responder just causes a weird focus-free situation that you can&#8217;t even tab out of.\n<\/p>\n<p>\nThe solution, I realized, was to detect the field editor being the first responder and, in that situation, treat its <em>delegate<\/em> as the responder that needs to be restored after editing. Now, I&#8217;m pretty sure that the delegate of a field editor will always be an NSResponder, but just to be sure, I do some runtime checking. The resulting code for &#8220;commit edits while saving and restoring the first responder&#8221; looks something like this:\n<\/p>\n<p><pre>\n<font size=\"-2\">\n\/\/ Save the current first responder, respecting the fact\n\/\/ that it might conceptually be the delegate of the \n\/\/ field editor that is \"first responder.\"\nid oldFirstResponder = [oMainDocumentWindow firstResponder];\nif ((oldFirstResponder != nil) &&\n     [oldFirstResponder isKindOfClass:[NSTextView class]] &&\n     [(NSTextView*)oldFirstResponder isFieldEditor])\n{   \n   \/\/ A field editor's delegate is the view we're editing\n   oldFirstResponder = [oldFirstResponder delegate];\n   if ([oldFirstResponder isKindOfClass:[NSResponder class]] == NO)\n   {\n      \/\/ Eh ... we'd better back off if \n      \/\/ this thing isn't a responder at all\n      oldFirstResponder = nil;\n   }\n} \n\n\/\/ Gracefully end all editing in our window (from Erik Buck).\n\/\/ This will cause the user's changes to be committed.\nif([oMainDocumentWindow makeFirstResponder:oMainDocumentWindow])\n{\n   \/\/ All editing is now ended and delegate messages sent etc.\n}\nelse\n{\n   \/\/ For some reason the text object being edited will\n   \/\/ not resign first responder status so force an \n   \/\/\/ end to editing anyway\n   [oMainDocumentWindow endEditingFor:nil];\n}\n\n\/\/ If we had a first responder before, restore it\nif (oldFirstResponder != nil)\n{\n   [oMainDocumentWindow makeFirstResponder:oldFirstResponder];\n}\n<\/font><\/pre>\n<\/p>\n<p>\nThis works perfectly for my needs and hopefully it will at least put you on the right path towards making your app work perfectly, too.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In general, a user&#8217;s changes to a Cocoa NSTextField are saved when they finish editing (by tabbing or clicking to another field) or press return. This is fine, and it works 95% of the time. But on occasion we may find good reason to saved a user&#8217;s changes regardless of whether they&#8217;ve performed one of [&hellip;]<\/p>\n","protected":false},"author":10,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[11,15],"tags":[],"class_list":["post-229","post","type-post","status-publish","format-standard","hentry","category-cocoa","category-programming"],"_links":{"self":[{"href":"https:\/\/redsweater.com\/blog\/wp-json\/wp\/v2\/posts\/229","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/redsweater.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/redsweater.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/redsweater.com\/blog\/wp-json\/wp\/v2\/users\/10"}],"replies":[{"embeddable":true,"href":"https:\/\/redsweater.com\/blog\/wp-json\/wp\/v2\/comments?post=229"}],"version-history":[{"count":0,"href":"https:\/\/redsweater.com\/blog\/wp-json\/wp\/v2\/posts\/229\/revisions"}],"wp:attachment":[{"href":"https:\/\/redsweater.com\/blog\/wp-json\/wp\/v2\/media?parent=229"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/redsweater.com\/blog\/wp-json\/wp\/v2\/categories?post=229"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/redsweater.com\/blog\/wp-json\/wp\/v2\/tags?post=229"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}