{"id":186,"date":"2008-12-19T15:51:56","date_gmt":"2008-12-19T20:51:56","guid":{"rendered":"http:\/\/vgable.com\/blog\/2008\/12\/19\/undocumented-automatorframework-goodness-actions-library\/"},"modified":"2008-12-19T15:51:59","modified_gmt":"2008-12-19T20:51:59","slug":"undocumented-automatorframework-goodness-actions-library","status":"publish","type":"post","link":"https:\/\/vgable.com\/blog\/2008\/12\/19\/undocumented-automatorframework-goodness-actions-library\/","title":{"rendered":"Undocumented Automator.framework Goodness: Actions Library"},"content":{"rendered":"<p>In Leopard, Apple introduced <a href=\"http:\/\/developer.apple.com\/DOCUMENTATION\/AppleApplications\/Reference\/AMWorkflowView_Class\/Reference\/Introduction.html\"><code>AMWorkflowView<\/code><\/a> and <a href=\"http:\/\/developer.apple.com\/DOCUMENTATION\/AppleApplications\/Reference\/AMWorkflowController_class\/index.html\"><code>AMWorkflowController<\/code><\/a>, which let you easily add automator-editing capabilities to your application (modulo <a href=\"http:\/\/vgable.com\/blog\/2008\/12\/18\/automator-bugs\/\">bugs!<\/a>)<\/p>\n<p>Obviously, for editing a workflow to be useful, you need to be able to add actions to it.  And to do that, you need to be able to browse and search actions.  But the current Automator.framework has no official support for doing this.<\/p>\n<p>But there are undocumented private APIs, which <a href=\"file:\/\/localhost\/Applications\/Automator.app\/\">Automator.app (link launches it)<\/a> uses&#8230;<\/p>\n<h3>How to Find Them<\/h3>\n<p><a href=\"http:\/\/www.codethecode.com\/projects\/class-dump\/\">class-dump<\/a> is an amazingly useful command-line tool that lets you generate headers from a compiled Objective-C binary.  Download it, and point it at <code>\/System\/Library\/Frameworks\/Automator.framework\/Automator<\/code>, to see everything Automator.framework <em>really<\/em> lets you do.<\/p>\n<h3>Instant Library Panel<\/h3>\n<p>The most useful definition I found was,<br \/>\n<code>@interface NSApplication (AMLibraryPanel)<br \/>\n- (void)orderFrontAutomatorLibraryPanel:(id)sender;<br \/>\n@end<br \/><\/code><\/p>\n<p><strong>Calling <code>[NSApp orderFrontAutomatorLibraryPanel:nil];<\/code> will show a panel with the same action-library view Automator has.<br \/>\n<\/strong><\/p>\n<p>This is what I&#8217;m using right now in <a href=\"http:\/\/vincentgable.com\/imlocation\/\">IMLocation<\/a> to let people find actions for workflows.  I don&#8217;t like the idea of using private APIs.  But I like the idea of implementing my own <code>AMLibraryView<\/code> replacement even less.  It would be a <em>lot<\/em> of work to make it as good as the real thing.  Any differences give users a fractured experience &#8212; one way to do something in Automator, another in my program.  And I would get dismal ROI, because I expect Apple to expose this functionality in the (near) future.<\/p>\n<p>(I also wouldn&#8217;t be so bullish on using private APIs if I didn&#8217;t have workarounds in place right now.  The only way <code>orderFrontAutomatorLibraryPanel:<\/code> gets called is if a user presses a &#8220;Show Actions&#8221; button on the toolbar.  That same toolbar has an &#8220;Open in Automator&#8221; button that opens the worklfow in Automator, where they can edit it without bugs.  So even if <code>orderFrontAutomatorLibraryPanel:<\/code> stopped working tomorrow, users could still do everything they could before &#8212; albeit less elegantly).<\/p>\n<h3>Looking Just Like Automator<\/h3>\n<p><strong>I don&#8217;t recommend doing this<\/strong>, but I&#8217;ve been able to embed an <code>AMLibraryView<\/code> in an <code>NSSplitView<\/code> next to an <code>AMWorkflowView<\/code>, to get a more Automator.app-like appearance.<\/p>\n<p>Here&#8217;s how I did it, given the <code>IBOutlet<\/code>s <code>workflowViewAndLibrarySplitView<\/code> which is an <code>NSSplit<\/code> view with an <code>AMWorkflowView<\/code> in one side, and the other side&#8217;s view connected to the outlet <code>workflowLibraryView<\/code>,<\/p>\n<p><code>[workflowViewAndLibrarySplitView replaceSubview:workflowLibraryView with:[[AMLibraryPanel sharedLibraryPanel] _libraryView]];<\/code><\/p>\n<p>Will put the library view inside your split view.<\/p>\n<p>Of course this screws up <code>orderFrontAutomatorLibraryPanel:<\/code>.  And I would not expect it to work in two windows.  And it&#8217;s using an underscore-private method of an already private and undocumented API.  That&#8217;s just to too risky for me; so I stick with the panel.  It gets the job done with one line of code, and that&#8217;s good enough for me.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In Leopard, Apple introduced AMWorkflowView and AMWorkflowController, which let you easily add automator-editing capabilities to your application (modulo bugs!) Obviously, for editing a workflow to be useful, you need to be able to add actions to it. And to do that, you need to be able to browse and search actions. But the current Automator.framework [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[6,38,3,5,4,93],"tags":[260,261,258,75,73,255],"class_list":["post-186","post","type-post","status-publish","format-standard","hentry","category-cocoa","category-interface-builder","category-macosx","category-objective-c","category-programming","category-reverse-engineering","tag-amlibrarypanel","tag-amlibraryview","tag-amworkflowcontroller","tag-amworkflowview","tag-automator","tag-bad-idea"],"_links":{"self":[{"href":"https:\/\/vgable.com\/blog\/wp-json\/wp\/v2\/posts\/186","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/vgable.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/vgable.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/vgable.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/vgable.com\/blog\/wp-json\/wp\/v2\/comments?post=186"}],"version-history":[{"count":0,"href":"https:\/\/vgable.com\/blog\/wp-json\/wp\/v2\/posts\/186\/revisions"}],"wp:attachment":[{"href":"https:\/\/vgable.com\/blog\/wp-json\/wp\/v2\/media?parent=186"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/vgable.com\/blog\/wp-json\/wp\/v2\/categories?post=186"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/vgable.com\/blog\/wp-json\/wp\/v2\/tags?post=186"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}