{"id":30,"date":"2007-09-09T21:05:13","date_gmt":"2007-09-10T05:05:13","guid":{"rendered":"http:\/\/www.latenightsw.com\/blog\/?p=49"},"modified":"2007-09-09T21:05:13","modified_gmt":"2007-09-10T05:05:13","slug":"cocoa-scripting-properties-with-multiple-data-types","status":"publish","type":"post","link":"https:\/\/markalldritt.com\/?p=30","title":{"rendered":"Cocoa Scripting: Properties with Multiple Data Types"},"content":{"rendered":"<p>The SDEF (Scripting Definition) XML dictionary format allows you to define properties that have multiple data types.  This allows applications to support the <em>as<\/em> parameter to the AppleScript <em>Get<\/em> command.  However, Cocoa Scripting does not fully support the notion of properties with multiple data types.  This article describes how to implement multiple data type support using Cocoa Scripting.<\/p>\n\n<h4>Why Do This?<\/h4>\n\n<p>Before I get into the code, let me briefly describe why you might want to do this in your application.  Simply put, the value of certain properties may be expressed in difference data types.  For example, you might have a <em>selection<\/em> property.  Lets say that by default, the selection property returns the selected text in your application.  However, you may also want to allow the user to ask for a reference to the location of the selected text:<\/p>\n\n<pre>\nget selection --> \"Hello World\"\nget selection as string --> \"Hello World\"\nget selection as reference --> word 2 thru 3 of document 1\n<\/pre>\n\n<p>When the scripter tries to alter the selection, they may do it in two ways:<\/p>\n\n<pre>\nset selection to \"Goodbye\" --> Replace the selected text with \"Goodbye\"\nset selection to word 1 of document 1 --> select the first word\n<\/pre>\n\n<p><strong>CAUTION<\/strong>: please use multiple data types correctly.  The value returned for each data type should represent the same <em>value<\/em>, but in different ways. Correct use of multiple types avoids the need to have multiple versions of a given property in your dictionary, each returning the same value expressed in a different way.<\/p>\n\n<h4>The SDEF<\/h4>\n\n<p>Here&#8217;s a snippet from an SDEF defining a <em>selection<\/em> property that supports two data types: text and specifier.<\/p>\n\n<pre>\n  <property name=\"selection\" ... >\n    <cocoa key=\"AESelection\" \/>\n    <type type=\"text\" \/>\n    <type type=\"specifier\" \/>\n  <\/property>\n<\/pre>\n\n<h4>Supporting Set Operations (Easy)<\/h4>\n\n<p>Cocoa Scripting facilitates Set operations for properties with multiple types.  It will convert the incoming AppleEvent data to an instance of NSString for a text value or an instance of NSScriptObjectSpecifier if the value is an object reference (specifier).  Here&#8217;s how you might implement the setAESelection: accessor:<\/p>\n\n<pre>\n- (void) setAESelection:(id) value\n{\n  if ([value isKindOfClass:[NSString class]])\n  {\n    \/\/ replace the selected text with the incoming value\n  }\n  else if ([value isKindOfClass:[NSScriptObjectSpecifier class]])\n  {\n    \/\/ change the selection to the range of text specified in the\n    \/\/ incoming object specifier\n  }\n}\n<\/pre>\n\n<h4>Supporting Get-As Operations (A Little Harder)<\/h4>\n\n<p>Here is where Cocoa Scripting leaves you to your own devices.  The problem is that the desired data type is not passed to the accessor function.  You have to get this from the current AppleEvent yourself.  I use this function:<\/p>\n\n<pre>\nDescType FSRequestedTypeForCurrentEvent()\n{\n  NSAppleEventDescriptor* event = [[NSAppleEventManager sharedAppleEventManager] currentAppleEvent];\n  NSAppleEventDescriptor* requestedType = [event descriptorForKeyword:keyAERequestedType];\n\n  if (requestedType)\n    return [requestedType typeCodeValue];\n  else\n    return typeBest;\n}\n<\/pre>\n\n<p>Then, the Accessor can be written like this:<\/p>\n\n<pre>\n- (id) AESelection\n{\n    switch (FSRequestedTypeForCurrentEvent())\n    {\n    case typeBest:  \/\/ the default if no 'as' parameter specified\n    case typeText:\n    case typeUnicodeText:\n        \/\/ return an NSString instance containing the selected string\n        break;\n\n    case typeObjectSpecifier:\n        \/\/ return an NSScriptObjectSpecifier instance describing the\n        \/\/ location of the selection\n        break;\n\n    default: \/\/ unsupported type\n        [[NSScriptCommand currentCommand] setScriptErrorNumber: errAEWrongDataType];\n        return nil;\n    }\n}\n<\/pre>\n\n<p><strong>NOTE<\/strong>: I generally have AppleEvent specific accessors for use with Cocoa Scripting that in turn use my bindings compatible accessors.  This is because Cocoa Scripting needs to support things like multiple data types, and reports errors in a different way.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The SDEF (Scripting Definition) XML dictionary format allows you to define properties that have multiple data types. This allows applications to support the as parameter&#8230;<div class=\"more-link-wrapper\"><a class=\"more-link\" href=\"https:\/\/markalldritt.com\/?p=30\">Continue Reading<span class=\"screen-reader-text\">Cocoa Scripting: Properties with Multiple Data Types<\/span><\/a><\/div><\/p>","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"jetpack_publicize_message":"","jetpack_is_tweetstorm":false,"jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","enabled":false}}},"categories":[6,8,9],"tags":[],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p7AQk-u","_links":{"self":[{"href":"https:\/\/markalldritt.com\/index.php?rest_route=\/wp\/v2\/posts\/30"}],"collection":[{"href":"https:\/\/markalldritt.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/markalldritt.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/markalldritt.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/markalldritt.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=30"}],"version-history":[{"count":0,"href":"https:\/\/markalldritt.com\/index.php?rest_route=\/wp\/v2\/posts\/30\/revisions"}],"wp:attachment":[{"href":"https:\/\/markalldritt.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=30"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/markalldritt.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=30"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/markalldritt.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=30"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}