appfactory 0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,168 @@
1
+ #
2
+ # Code stolen from HotCocoa examples: http://macruby.org
3
+ #
4
+ module Growl
5
+ class Notifier
6
+ VERSION = '1.0.1'
7
+
8
+ GROWL_IS_READY = "Lend Me Some Sugar; I Am Your Neighbor!"
9
+ GROWL_NOTIFICATION_CLICKED = "GrowlClicked!"
10
+ GROWL_NOTIFICATION_TIMED_OUT = "GrowlTimedOut!"
11
+ GROWL_KEY_CLICKED_CONTEXT = "ClickedContext"
12
+
13
+ PRIORITIES = {
14
+ :emergency => 2,
15
+ :high => 1,
16
+ :normal => 0,
17
+ :moderate => -1,
18
+ :very_low => -2,
19
+ }
20
+
21
+ class << self
22
+ # Returns the singleton instance of Growl::Notifier with which you register and send your Growl notifications.
23
+ def sharedInstance
24
+ @sharedInstance ||= alloc.init
25
+ end
26
+ end
27
+
28
+ attr_reader :application_name, :application_icon, :notifications, :default_notifications
29
+ attr_accessor :delegate
30
+
31
+ # Registers the applications metadata and the notifications, that your application might send, to Growl.
32
+ # The +default_notifications+ are notifications that will be enabled by default, the regular +notifications+ are
33
+ # optional and should be enabled by the user in the Growl system preferences.
34
+ #
35
+ # Register the applications name and the notifications that will be used.
36
+ # * +default_notifications+ defaults to the regular +notifications+.
37
+ # * +application_icon+ defaults to NSApplication.sharedApplication.applicationIconImage.
38
+ #
39
+ # Growl::Notifier.sharedInstance.register 'FoodApp', ['YourHamburgerIsReady', 'OhSomeoneElseAteIt']
40
+ #
41
+ # Register the applications name, the notifications plus the default notifications that will be used and the icon that's to be used in the Growl notifications.
42
+ #
43
+ # Growl::Notifier.sharedInstance.register 'FoodApp', ['YourHamburgerIsReady', 'OhSomeoneElseAteIt'], ['DefaultNotification], NSImage.imageNamed('GreasyHamburger')
44
+ def register(application_name, notifications, default_notifications = nil, application_icon = nil)
45
+ @application_name, @application_icon = application_name, (application_icon || NSApplication.sharedApplication.applicationIconImage)
46
+ @notifications, @default_notifications = notifications, (default_notifications || notifications)
47
+ @callbacks = {}
48
+ send_registration!
49
+ end
50
+
51
+ # Sends a Growl notification.
52
+ #
53
+ # * +notification_name+ : the name of one of the notifcations that your apllication registered with Growl. See register for more info.
54
+ # * +title+ : the title that should be used in the Growl notification.
55
+ # * +description+ : the body of the Grow notification.
56
+ # * +options+ : specifies a few optional options:
57
+ # * <tt>:sticky</tt> : indicates if the Grow notification should "stick" to the screen. Defaults to +false+.
58
+ # * <tt>:priority</tt> : sets the priority level of the Growl notification. Defaults to 0.
59
+ # * <tt>:icon</tt> : specifies the icon to be used in the Growl notification. Defaults to the registered +application_icon+, see register for more info.
60
+ #
61
+ # Simple example:
62
+ #
63
+ # name = 'YourHamburgerIsReady'
64
+ # title = 'Your hamburger is ready for consumption!'
65
+ # description = 'Please pick it up at isle 4.'
66
+ #
67
+ # Growl::Notifier.sharedInstance.notify(name, title, description)
68
+ #
69
+ # Example with optional options:
70
+ #
71
+ # Growl::Notifier.sharedInstance.notify(name, title, description, :sticky => true, :priority => 1, :icon => NSImage.imageNamed('SuperBigHamburger'))
72
+ #
73
+ # When you pass notify a block, that block will be used as the callback handler if the Growl notification was clicked. Eg:
74
+ #
75
+ # Growl::Notifier.sharedInstance.notify(name, title, description, :sticky => true) do
76
+ # user_clicked_notification_so_do_something!
77
+ # end
78
+ def notify(notification_name, title, description, options = {}, &callback)
79
+ dict = {
80
+ :ApplicationName => @application_name,
81
+ :ApplicationPID => pid,
82
+ :NotificationName => notification_name,
83
+ :NotificationTitle => title,
84
+ :NotificationDescription => description,
85
+ :NotificationPriority => PRIORITIES[options[:priority]] || options[:priority] || 0
86
+ }
87
+ dict[:NotificationIcon] = options[:icon].TIFFRepresentation if options[:icon]
88
+ dict[:NotificationSticky] = 1 if options[:sticky]
89
+
90
+ context = {}
91
+ context[:user_click_context] = options[:click_context] if options[:click_context]
92
+ if block_given?
93
+ @callbacks[callback.object_id] = callback
94
+ context[:callback_object_id] = callback.object_id.to_s
95
+ end
96
+ dict[:NotificationClickContext] = context unless context.empty?
97
+
98
+ notification_center.postNotificationName :GrowlNotification, object:nil, userInfo:dict, deliverImmediately:true
99
+ end
100
+
101
+ def onReady(notification)
102
+ send_registration!
103
+ end
104
+
105
+ def onClicked(notification)
106
+ user_context = nil
107
+ if context = notification.userInfo[GROWL_KEY_CLICKED_CONTEXT]
108
+ user_context = context[:user_click_context]
109
+ if callback_object_id = context[:callback_object_id]
110
+ @callbacks.delete(callback_object_id.to_i).call
111
+ end
112
+ end
113
+
114
+ @delegate.growlNotifierClicked_context(self, user_context) if @delegate && @delegate.respond_to?(:growlNotifierClicked_context)
115
+ end
116
+
117
+ def onTimeout(notification)
118
+ user_context = nil
119
+ if context = notification.userInfo[GROWL_KEY_CLICKED_CONTEXT]
120
+ @callbacks.delete(context[:callback_object_id].to_i) if context[:callback_object_id]
121
+ user_context = context[:user_click_context]
122
+ end
123
+
124
+ @delegate.growlNotifierTimedOut_context(self, user_context) if @delegate && @delegate.respond_to?(:growlNotifierTimedOut_context)
125
+ end
126
+
127
+ private
128
+
129
+ def pid
130
+ NSProcessInfo.processInfo.processIdentifier.to_i
131
+ end
132
+
133
+ def notification_center
134
+ NSDistributedNotificationCenter.defaultCenter
135
+ end
136
+
137
+ def send_registration!
138
+ add_observer 'onReady:', GROWL_IS_READY, false
139
+ add_observer 'onClicked:', GROWL_NOTIFICATION_CLICKED, true
140
+ add_observer 'onTimeout:', GROWL_NOTIFICATION_TIMED_OUT, true
141
+
142
+ dict = {
143
+ :ApplicationName => @application_name,
144
+ :ApplicationIcon => application_icon.TIFFRepresentation,
145
+ :AllNotifications => @notifications,
146
+ :DefaultNotifications => @default_notifications
147
+ }
148
+
149
+ notification_center.postNotificationName :GrowlApplicationRegistrationNotification, object:nil, userInfo:dict, deliverImmediately:true
150
+ end
151
+
152
+ def add_observer(selector, name, prepend_name_and_pid)
153
+ name = "#{@application_name}-#{pid}-#{name}" if prepend_name_and_pid
154
+ notification_center.addObserver self, selector:selector, name:name, object:nil
155
+ end
156
+ end
157
+
158
+ def self.growl(name, title, description, options = {}, &callback)
159
+ Growl::Notifier.sharedInstance.notify name, title, description, options, &callback
160
+ end
161
+
162
+ # Sends a sticky Growl notification. See Growl::Notifier#notify for more info.
163
+ def self.sticky_growl(name, title, description, options = {}, &callback)
164
+ growl name, title, description, options.merge!(:sticky => true), &callback
165
+ end
166
+
167
+
168
+ end
@@ -0,0 +1,171 @@
1
+ framework 'Cocoa'
2
+ $: << NSBundle.mainBundle.resourcePath.fileSystemRepresentation
3
+ require 'growl'
4
+
5
+ module AppFactory
6
+ def self.resources_dir
7
+ NSBundle.mainBundle.resourcePath.fileSystemRepresentation
8
+ end
9
+
10
+ def self.app_name
11
+ @app_name || 'AppFactory'
12
+ end
13
+
14
+ def self.app_name=(name)
15
+ @app_name = name
16
+ end
17
+
18
+ def self.debug(msg)
19
+ NSLog "DEBUG [#{app_name}]: #{msg}"
20
+ end
21
+
22
+ def register_growl_events(array = [])
23
+ a = array.map { |e| e.to_s }
24
+ Growl::Notifier.sharedInstance.register AppFactory.app_name, array
25
+ end
26
+
27
+ def growl(event_name, title, desc)
28
+ Growl.growl event_name.to_s, title, desc
29
+ end
30
+
31
+ def self.top_menu
32
+ if not @top_menu
33
+ @top_menu = NSMenu.new
34
+ @top_menu.initWithTitle app_name
35
+ @top_menu
36
+ else
37
+ debug 'Meny already initialized...'
38
+ @top_menu
39
+ end
40
+ end
41
+
42
+ def clear_menu(menu)
43
+ menu.itemArray.each do |mi|
44
+ menu.removeItem mi
45
+ end
46
+ end
47
+
48
+ def self.terminate
49
+ @app.terminate(self)
50
+ end
51
+
52
+ def open_url(url)
53
+ NSWorkspace.sharedWorkspace.openURL(NSURL.URLWithString(url))
54
+ end
55
+
56
+ def self.status_bar
57
+ if not @status_bar
58
+ @status_bar = NSStatusBar.systemStatusBar
59
+ @status_item = @status_bar.statusItemWithLength(NSVariableStatusItemLength)
60
+ @status_item.setMenu top_menu
61
+ img = NSImage.new.initWithContentsOfFile "#{AppFactory.resources_dir}/ruby_statusbar.png"
62
+ @status_item.setImage(img)
63
+ Growl.growl 'InitDone', app_name, "Here we go!"
64
+ @status_bar
65
+ else
66
+ debug 'Statusbar already initialized...'
67
+ @status_bar
68
+ end
69
+ end
70
+
71
+ def self.start
72
+ @app = NSApplication.sharedApplication
73
+ status_bar
74
+ @app.run
75
+ end
76
+
77
+ def timer(interval, &block)
78
+ delegate = TimerDelegate.new
79
+ @timer = NSTimer.scheduledTimerWithTimeInterval interval.to_f, :target => delegate, :selector => "runTimer:", :userInfo => nil, :repeats => true
80
+ TimerDelegate.send(:class_eval, "def timerBlock=(blk); @timerBlock = blk; end")
81
+ delegate.send("timerBlock=".to_sym, block)
82
+ end
83
+
84
+ def menu_item(title, &block)
85
+ mi = NSMenuItem.new
86
+ mi.title = title
87
+ dname = "delegate#{rand(999999999)}"
88
+ mi.action = "#{dname}:"
89
+ AppFactoryDelegate.send(:class_eval, "def #{dname}=(blk); @#{dname} = blk; end")
90
+ AppFactoryDelegate.send(:class_eval, "def #{dname}(sender); @#{dname}.call ; end")
91
+ delegate = AppFactory.delegate
92
+ delegate.send("#{dname}=".to_sym, block)
93
+ mi.target = delegate
94
+ if @current_menu
95
+ @current_menu.addItem mi
96
+ else
97
+ AppFactory.menu.addItem mi
98
+ end
99
+ end
100
+
101
+ def menu_separator
102
+ if @current_menu
103
+ @current_menu.addItem NSMenuItem.separatorItem
104
+ else
105
+ puts NSMenuItem.separatorItem
106
+ AppFactory.top_menu.addItem NSMenuItem.separatorItem
107
+ end
108
+ end
109
+
110
+ def menu_quit
111
+ mi = NSMenuItem.new
112
+ mi.title = 'Quit'
113
+ mi.action = 'terminate:'
114
+ mi.target = AppFactory.delegate
115
+ AppFactory.top_menu.addItem mi
116
+ end
117
+
118
+ def menu(title)
119
+ if not @submenues
120
+ AppFactory.debug 'Init submenues collection'
121
+ @submenues = {}
122
+ end
123
+ m = nil
124
+ if @submenues.has_key? title
125
+ #existing menu
126
+ AppFactory.debug "Submenu #{title} already exists"
127
+ m = @submenues[title]
128
+ else
129
+ AppFactory.debug "Creating submenu #{title}"
130
+ m = NSMenu.new
131
+ @submenues[title] = m
132
+ m.initWithTitle title
133
+ mi = NSMenuItem.new
134
+ mi.title = title
135
+ mi.setSubmenu m
136
+ AppFactory.top_menu.addItem mi
137
+ end
138
+ @current_menu = m
139
+ yield m
140
+ @current_menu = nil
141
+ end
142
+
143
+ def self.delegate
144
+ @delegate ||= AppFactoryDelegate.new
145
+ end
146
+
147
+ def self.vendor_libs
148
+ Dir["#{resources_dir}/vendor/gems/gems/*"].each do |d|
149
+ AppFactory.debug "Adding #{d}/lib to RUBYLIB"
150
+ $: << "#{d}/lib"
151
+ end
152
+ end
153
+
154
+ class TimerDelegate
155
+ def runTimer(timer)
156
+ @timerBlock.call
157
+ end
158
+ end
159
+ class AppFactoryDelegate
160
+ def terminate(sender)
161
+ AppFactory.terminate
162
+ end
163
+ end
164
+
165
+ end
166
+
167
+ AppFactory.vendor_libs
168
+ include AppFactory
169
+ require 'dsl'
170
+
171
+ AppFactory.start
metadata ADDED
@@ -0,0 +1,105 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: appfactory
3
+ version: !ruby/object:Gem::Version
4
+ version: "0.1"
5
+ platform: ruby
6
+ authors:
7
+ - Sergio Rubio
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-12-02 00:00:00 +01:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: choice
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 0.1.3
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: bundler
27
+ type: :runtime
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: "0.7"
34
+ version:
35
+ - !ruby/object:Gem::Dependency
36
+ name: hoe
37
+ type: :development
38
+ version_requirement:
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: 2.3.3
44
+ version:
45
+ description: Easily create Status Bar Applications for Mac OS X
46
+ email:
47
+ - sergio@rubio.name
48
+ executables:
49
+ - appfactory
50
+ extensions: []
51
+
52
+ extra_rdoc_files:
53
+ - History.txt
54
+ - Manifest.txt
55
+ - README.txt
56
+ files:
57
+ - .DS_Store
58
+ - History.txt
59
+ - Manifest.txt
60
+ - README.txt
61
+ - Rakefile
62
+ - bin/appfactory
63
+ - examples/appmain.rb
64
+ - lib/appfactory.rb
65
+ - template/appfactory.app.template/Contents/Info.plist
66
+ - template/appfactory.app.template/Contents/MacOS/appfactory
67
+ - template/appfactory.app.template/Contents/PkgInfo
68
+ - template/appfactory.app.template/Contents/Resources/English.lproj/InfoPlist.strings
69
+ - template/appfactory.app.template/Contents/Resources/English.lproj/MainMenu.nib/designable.nib
70
+ - template/appfactory.app.template/Contents/Resources/English.lproj/MainMenu.nib/keyedobjects.nib
71
+ - template/appfactory.app.template/Contents/Resources/growl.rb
72
+ - template/appfactory.app.template/Contents/Resources/rb_main.rb
73
+ - template/appfactory.app.template/Contents/Resources/ruby.icns
74
+ - template/appfactory.app.template/Contents/Resources/ruby_statusbar.png
75
+ has_rdoc: true
76
+ homepage: http://appfactory.netcorex.org
77
+ licenses: []
78
+
79
+ post_install_message:
80
+ rdoc_options:
81
+ - --main
82
+ - README.txt
83
+ require_paths:
84
+ - lib
85
+ required_ruby_version: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: "0"
90
+ version:
91
+ required_rubygems_version: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: "0"
96
+ version:
97
+ requirements: []
98
+
99
+ rubyforge_project: appfactory
100
+ rubygems_version: 1.3.5
101
+ signing_key:
102
+ specification_version: 3
103
+ summary: Mac OS X StatusBar App Builder!
104
+ test_files: []
105
+