AppleScriptObjC in Xcode Part 3 - Customizing Templates

In the “Cocoa - AppleScript” template that comes with Xcode 3.2 there are a few changes that you might want to make.

Here are two examples.

  1. Change “my NSTerminateNow” to either “true”, “1” or “my NSTerminateNow as integer”
  2. Add property parent : “NSObject”

This is a short tutorial demonstrating how to do just that.

Where are the default templates located?
Default templates are located in:

There are two templates in this folder.
1. Cocoa-AppleScript Application
2. Cocoa-AppleScript Document-based Application

If you look inside the first folder these are the files you will see.


File List

Make a backup of this folder before making changes.
This is for convenience since you can get the original files from the Snow Leopard install disk.

Which file to change?
The file you want to open is:

The default template is pretty plain. Take note not to alter any of the constants; those names with triple underscores around them like “DATE.”

Example Template
Here is what I changed mine to look like. You may not like what I have done and that is why you customize it for yourself!


--
--  ___PROJECTNAMEASIDENTIFIER___AppDelegate.applescript
--  ___PROJECTNAME___
--
--  Created by ___FULLUSERNAME___ on ___DATE___.
--  Copyright ___YEAR___ ___ORGANIZATIONNAME___. All rights reserved.
--

script ___PROJECTNAMEASIDENTIFIER___AppDelegate
	-- Inheritance
	property parent : class "NSObject"
	
	-- IBOutlets
	-- property NAME : missing value
	-- property NAME : missing value
	
	-- IBActions ( button clicks )	
	on doAction_(sender)
		
	end
	
	##################################################
	# Application
	
	on awakeFromNib()
		-- Code here
	end awakeFromNib
	
	on applicationWillFinishLaunching_(aNotification)
		-- Insert code here to initialize your application before any files are opened 
	end applicationWillFinishLaunching_
	
	on applicationShouldTerminate_(sender)
		-- Insert code here to do any housekeeping before your application quits 
		return true
	end applicationShouldTerminate_
	
end script

Creating New Templates!
So, what if you want to have your own set of templates for different situations, say table view, outline view, etc. There is a special place we need to put those templates on our hard drive. In fact, you may want to leave the default template alone and make all your changes in the “Users Templates.”

Where are user templates located?
You may need to create the “Project Templates” folder if it does not exists. Inside this folder I created a folder called “AppleScriptObjC” and that is where I will keep all of my custom templates. When I view this in Xcode all of my templates will be neatly organized into this folder.

User templates are located here.

First Template
Duplicate the “Cocoa-AppleScript Application” folder from the defaults template location into the folder you have chosen inside your users templates folder.

Two things you need to do for your template.

  1. The folder name of this template will be what is displayed in Xcode so name it something that is meaningful to its use. eg “Cocoa-AppleScript TableView.”
  2. Change the file “___PROJECTNAMEASIDENTIFIER___AppDelegate.applescript”, like we did above, to contain the specific code you desire.

Repeat this process for as many templates as you need!

When you create a new project in Xcode you will see your custom templates!


New Application Dialog

Get More From Xcode
Pragmatic Programmers has a series of videos, “Becoming Productive in Xcode” by Mike Clark, which covers many ways to use and customize Xcode. Check it out!

Until next time, happy coding!

Craig,

Thanks a million for all your help. This template business is the greatest…

Here is a copy of my first template, appropriately called, per the tutorial “Cocoa-AppleScript TableView”

Best Regards,

Bill Hernandez
Plano, Texas

– TEMPLATE PATH : ~/Library/Application Support/Developer/Shared/Xcode/Project Templates/Cocoa-AppleScript Application/Cocoa-AppleScript Application/
– TEMPLATE FILENAME : ___PROJECTNAMEASIDENTIFIER___AppDelegate.applescript

– ___PROJECTNAMEASIDENTIFIER___AppDelegate.applescript
PROJECTNAME

– Created by FULLUSERNAME on DATE.
– Copyright YEAR ORGANIZATIONNAME. All rights reserved.

– CREDIT to Craig Williams for all his work on the great tutorials,
– and to others whose contributions appear here.
– I don’t know any of them but they give a great deal to the rest of us…
– THANK YOU ALL…
(*
– ±--------±--------±--------±--------±--------±--------±--------±--------+
– [1000] PROJECT NOTES
– ±--------±--------±--------±--------±--------±--------±--------±--------+

-- +---------+---------+---------+---------+---------+---------+---------+---------+
-- [2000] STANDARD NOTES
-- +---------+---------+---------+---------+---------+---------+---------+---------+
At startup, event handlers attached to the application object are called in this order:
-- +---------+---------+---------+---------+---------+---------+---------+---------+
1. will finish launching
2. awake from nib
3. launched
4. will become active
5. activated
6. idle
-- +---------+---------+---------+---------+---------+---------+---------+---------+
-- To Open Documentation
-- Option DoubleClick on ---> NSTextView then click on the book icon
-- Option DoubleClick on ---> NSText then click on the book icon
-- +---------+---------+---------+---------+---------+---------+---------+---------+
-- DELETE, OR RENAME ANY OF THE CONTENT BELOW THAT YOU DON'T NEED
-- +---------+---------+---------+---------+---------+---------+---------+---------+

*)

script ___PROJECTNAMEASIDENTIFIER___AppDelegate
– ±--------±--------±--------±--------±--------±--------±--------±--------+
– [3000] PROPERTIES
– ±--------±--------±--------±--------±--------±--------±--------±--------+
– [3001] Inheritance
– ±--------±--------±--------±--------±--------±--------±--------±--------+
– Any Objective-C class you wish to access in your code must be set up as a property.
– ±--------±--------±--------±--------±--------±--------±--------±--------+
property parent : class “NSObject”

property NSMutableArray : class "NSMutableArray"		-- see also NSArray
property NSTextView : class "NSTextView"					-- see also NSText
property NSImage : class "NSImage"
-- +---------+---------+---------+---------+---------+---------+---------+---------+
-- [3002] IB_Outlets	
-- +---------+---------+---------+---------+---------+---------+---------+---------+
-- Interface Builder considers an outlet as any property with "missing value" as its value
-- an outlet is associated with a textField, textView, popupMenu, radioButtonGroup, etc
-- +---------+---------+---------+---------+---------+---------+---------+---------+
property aWindow : missing value
property tableView : missing value
property textView : missing value
property textField : missing value

property show_debug : false
-- +---------+---------+---------+---------+---------+---------+---------+---------+
-- [3003] IB_Bindings	
-- +---------+---------+---------+---------+---------+---------+---------+---------+
-- We connect these in the bindings inspector to the corresponding text field values.
--
-- Note: 
--			You cannot connect bindings directly to the NSTextFields above so we
--  		create new properties to hold the "value" of the NSTextFields.
-- +---------+---------+---------+---------+---------+---------+---------+---------+
(*
	property theAuthor : ""		-- variable used to bind to the actual field authorField
	property theBook : ""			-- variable used to bind to the actual field bookField
	property theStatus : ""		-- variable used to bind to the actual field statusRadioButton
*)

-- +---------+---------+---------+---------+---------+---------+---------+---------+
-- [3004] Other Properties
-- +---------+---------+---------+---------+---------+---------+---------+---------+
-- theDataSource will be an NSMutableArray We set this up in the awakeFromNib handler
-- +---------+---------+---------+---------+---------+---------+---------+---------+
property theDataSource : {}


-- +---------+---------+---------+---------+---------+---------+---------+---------+
-- [4000] ACTIONS
-- +---------+---------+---------+---------+---------+---------+---------+---------+
-- IB_Actions
-- +---------+---------+---------+---------+---------+---------+---------+---------+
-- Things like button clicks, tabbing out of a field, i.e. losing focus, 
-- selecting from a popup menu, radio button group, etc
--
-- Interface Builder considers an action as any
-- single parameter method ending with an underscore 
-- +---------+---------+---------+---------+---------+---------+---------+---------+
on updateItems_(sender)
	(*
		set selTitle to my updItems()
		set theTextView to (textView's stringValue()) as string
		set theTextField to (textField's stringValue()) as string
		tell textView
			setString_(theTextView & return & "[" & selTitle & "] " & theTextField)
		end tell
	*)
end updateItems_
-- +---------+---------+---------+---------+---------+---------+---------+---------+
-- [5000] SUPPORT FUNCTIONS 
-- +---------+---------+---------+---------+---------+---------+---------+---------+
-- These are functions that support the application functions, and IB_Action Methods
-- +---------+---------+---------+---------+---------+---------+---------+---------+
on get_time_stamp(which)
	if (which is 1) then
		set returnValue to do shell script "date '+[%Y.%m.%d](%I.%M.%S.%p)'"
		---> [2009.10.13](07.15.41.PM)
	else if (which is 2) then
		set returnValue to do shell script "date '+[ %Y.%m.%d ] ( %I.%M.%S.%p )'"
		---> [ 2009.10.13 ] ( 07.14.43.PM )
	else if (which is 3) then
		set returnValue to do shell script "date '+%Y.%m.%d_%I.%M.%S.%p'"
		---> 2009.10.13_07.15.15.PM
	else
		-- which is 1 or anything else
		set returnValue to do shell script "date '+[%Y.%m.%d](%I.%M.%S.%p)'"
		---> [2009.10.13](07.15.41.PM)
	end if
	return returnValue
end get_time_stamp
-- +---------+---------+---------+---------+---------+---------+---------+---------+
-- [6000] APPLICATION FUNCTIONS
-- +---------+---------+---------+---------+---------+---------+
on awakeFromNib()
	set time_stamp to my get_time_stamp(2) -- format choices { 1, 2, 3 }
	
	(*
		tell textView
			setTextContainerInset_({5.0, 5.0})
			setString_(time_stamp & "  |  " & "Bill Hernandez")
		end tell
		
		tell textField
			setStringValue_("Default text")
		end tell
	*)
	
	(*
		-- +---------+---------+---------+---------+---------+---------+---------+---------+
		-- WORKING WITH RADIO BUTTON GROUPS
		-- THIS CODE CAN GO IN ( 1 ) "on awakeFromNib" OR ( 2 )  "on applicationWillFinishLaunching_"
		-- +---------+---------+---------+---------+---------+---------+---------+---------+
		-- NSMatrix - used for radio buttons
		-- set the initial row to select for the radio button matrix
		-- aRadioButtonGroup's selectRow_byExtendingSelection_(1, true)
		aRadioButtonGroup's selectCellAtRow_column_(1, 0)
		
		set selRow to (aRadioButtonGroup's selectedRow())
		set selCell to (aRadioButtonGroup's selectedCell())
		set selTitle to (selCell's |title|())
		
		if (show_debug) then
			-- the [number] in the brackets below is arbitrary, but unique within a document, and represents 
			-- the exact location in the code, whether it be an info message, or error message, and helps when debugging
			set s to "[9721] "	
			set s to s & ("Selected Row is = " & selRow as string) & return
			set s to s & ("Selected Title is = " & selTitle as string)
			display dialog (s)
		end if
	*)
	
end awakeFromNib
-- +---------+---------+---------+---------+---------+---------+---------+---------+
on applicationWillFinishLaunching_(aNotification)
	-- Insert code here to initialize your application before any files are opened 
	(*
		-- +---------+---------+---------+---------+---------+---------+---------+---------+
		-- WORKING WITH POPUP MENUS
		-- THIS CODE CAN GO IN ( 1 ) "on awakeFromNib" OR ( 2 )  "on applicationWillFinishLaunching_"			
		-- Dynamically load a popup menu called startingMonth
		-- +---------+---------+---------+---------+---------+---------+---------+---------+
		-- Insert code to initialize your application before any files are opened 
		set theMonths to {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"}
		
		startingMonth's removeAllItems()
		startingMonth's addItemsWithTitles_(theMonths)
	*)
end applicationWillFinishLaunching_
-- +---------+---------+---------+---------+---------+---------+---------+---------+
on applicationShouldTerminate_(sender)
	-- +---------+---------+---------+---------+---------+---------+---------+---------+
	-- Insert code here to do any housekeeping before your application quits 
	-- SAVE DATA, window positions, last selected radio buttons, popup menus, column widths, etc.
	-- +---------+---------+---------+---------+---------+---------+---------+---------+
	try
		set returnValue to (current application's NSTerminateNow) as integer
	on error
		set returnValue to true
	end try
	return returnValue
end applicationShouldTerminate_
-- +---------+---------+---------+---------+---------+---------+---------+---------+

end script

Craig,

I created a few screen captures and some info for the User Templates

http://www.h2url.com/

Bill Hernandez
Plano, Texas

Nice job Bill and cool site too!

Craig,

I followed your link to Pragmatic Programmers website, and signed up for several video courses.

http://www.pragprog.com/screencasts

I have spent the last couple of days going through the “Coding in Objective C” by Bill Dudney.

I have gone through the first video twice completely, using my special looping method…

repeat(until concept is clear)
start
stop
take notes
rewind
end repeat

Anyway, I’ve got 25 pages of notes on the first ObjC video alone, this is great !

I am so excited, but there is a really scary part to all this. It is all beginning to make a lot of sense…

Anyway as I mentioned above, I signed up for several videos, and intend to sign up for some more.

Thanks for the great tip and all the help. I bet you didn’t realize that some of us read your stuff very carefully.

Bill Hernandez
Plano, Texas

BTW, I put your name in the discount coupon field, and they doubled the amount on the invoice.
Is this great, or what ?

I have not been able to get a user template or a user template category to show up in 4.2.
I copied and renamed the standard template, gave it a new unique identifier in TemplateInfo.plist, and put it in this path:

/Users/Ronzo/Library/Application Support/Developer/Shared/Xcode/Templates/Cocoa-AppleScript Application (User).xctemplate

I quit and restarted XCode, but it doesn’t show up. Any ideas?

(PS, if I instead put the above new template in the /Developer/Library/Xcode/Templates/Project Templates/Mac/Application/Cocoa-AppleScript Application (User).xctemplate,
then it does show up.

The format of templates has changed completely with Xcode 4. They now work with base templates, plus plist files describing how to change them. Making your own is considerably more challenging, alas.