ooRexx logo
   1: /* --------------------------------------------------------------------------------------- */
   2: /* No freakin' copyright, no stinkin' license, no guarantees or warranties                 */
   3: /* (implied, explicit or whatever). Usage is totally and completely at your own risk.      */
   4: /* Please keep this comment block as is when modifying this code. Thanks in advance,       */
   5: /*   Ruurd Idenburg                                                                        */
   6: /* --------------------------------------------------------------------------------------- */
   7: /**
   8: 	The eventable class is a mixin class, that can be used in the 
   9: 	inheriting class to define events (by name) and trigger those events so that
  10: 	other classes may act upon those events.
  11: 	

12: Events are defined as indexes in an events directory. The events directory 13: is created in the events instance init method and is therefore 14: available after the inheriting class instance creation has called it's super 15: class init method, so the logical thing to do is to define the 16: class instance events in the inheriting class init method for 17: new instances. However events can also be defined later on by the inheriting 18: class instance methods. 19:

20: Event handlers/listeners need to define an instance method with the name of 21: the defined event. That method will be invoked by the triggering of the event. 22: The handler/listener method should return the boolean .true or .false 23: depending on whether possible other handlers/listeners should be given the 24: opportunity to act on the event. Returning .false will allow other 25: handlers/listeners to be invoked as well, returning .true will stop 26: invoking other handlers/listeners. 27:

28: Handlers/Listeners are kept as members of an array that is the item in the 29: directory entry for the index that has the name of the event. 30: */ 31: ::class eventable public mixinclass object 32: 33: /** 34: The events attribute is a directory, whose entries can only be set privately 35: by the inheriting class instance methods. The directory is created in the 36: init instance method of this (the events) class. 37: */ 38: ::attribute events get 39: 40: ::attribute events set private 41: 42: /** 43: The init method creates the directory that will have the event 44: names as indexes and the array of handlers/listeners as items. 45:
46: @param eventArray=(.array~new) - optional, an array of event names provided by the inheriting class 47:

48: If an array with event names is provided, the entries are created in the events directory 49: with empty arrays as items to hold future handlers/listeners. 50: */ 51: ::method init 52: expose events 53: use strict arg eventArray=(.array~new) 54: events = .directory~new 55: if eventArray~class~id==.array then do 56: do a over eventArray 57: events[a] = .array~new 58: end 59: end 60: 61: /** 62: addEventHander is a synonym for addEventListener 63:
64: @see #addEventListener 65: */ 66: ::method addEventHandler 67: use strict arg event, handler 68: self~addEventListener(event, handler) 69: 70: /** 71: Adds an object to the group of interested parties 72:
73: @param event - the name of an event 74: @param listener - the object interested in that event 75:

76: If the array of handlers/listeners does not exist yet for the event it will 77: be created. The handler/listener object is appended to the existing or new array 78:

79: It is not verified if the event is a valid event for the object, the result for 80: that condition will be that the handler/listener will never be invoked. 81:

82: The same handler/listener can be added multiple times, if for some reason that 83: would be necessary for proper functioning and provided some earlier handler/listener 84: did not return .true. 85: */ 86: ::method addEventListener 87: expose events 88: --trace i 89: use strict arg event, listener 90: if events[event]==.nil then do 91: events[event] = .array~new 92: end 93: events[event]~append(listener) 94: 95: /** 96: removeEventHandler is a synonym for removeEventListener 97:
98: @see #removeEventListener 99: */ 100: ::method removeEventHandler 101: use strict arg event, handler 102: self~removeEventListener(event, handler) 103: 104: /** 105: Removes a party from the group interested in an event 106:
107: @param event - the name of an event 108: @param listener - the handler/listener object to be removed 109:

110: If the event is not known, the object can not be removed obviously 111:
112: If the listener is not a member of the interested handlers/listeners, 113: nothing can be removed. 114:
115: The handlers/listeners will be regenerated to prevent sparseness. 116: */ 117: ::method removeEventListener 118: expose events 119: --trace i 120: use strict arg event, listener 121: if events[event]~class~id==.array then do 122: events[event]~removeItem(listener) 123: events[event] = events[event]~makeArray 124: end 125: 126: /** 127: Returns the list of defined events for the object 128:
129: @return anArray - an array of event names for the object 130:

131: The array can be empty if no events have been defined 132: */ 133: ::method eventNames 134: use strict arg 135: return self~events~makeArray 136: 137: /** 138: eventHandlers is a synonym for eventListeners 139:
140: @see #eventListeners 141: */ 142: ::method eventHandlers 143: use strict arg event 144: return self~eventListeners(event) 145: 146: /** 147: Returns an array of handlers/listeners for an event. 148:
149: @param event - the name of an event 150: @return anArray - an array of handlers/listeners for an event 151:

152: The returned array can be empty if there are no listeners for the event 153: or if the event is unknown. 154: */ 155: ::method eventListeners 156: expose events 157: use strict arg event 158: if events[event]~isA(.array) then return events[event] 159: return .array~new 160: 161: /** 162: Invokes the event handling method in the handlers/listeners for an 163: event while successive handlers/listeners return .false, and stops 164: to invoke following handlers/listeners on the first .true return. 165:
166: @expose events - the directory of triggerable events for the class 167: @param event - the name of the event to be handled 168: @param args=(.array~new) - optional arguments for the handler method 169:

170: */ 171: ::method triggerEvent 172: expose events 173: --trace i 174: use strict arg event, args=(.array~new) 175: if events[event]==.nil then do 176: --.error~lineout('Event:' event 'is not defined') 177: return 178: end 179: if events[event]~items==0 then do 180: --.error~lineout('Event:' event 'does not have listeners') 181: return 182: end 183: result = .false 184: do l over events[event] while result==.false 185: if l~hasMethod(event) then do 186: msg = .message~new(l,event,'I',args~makeString('L',',')) 187: --.traceoutput~say(msg~messageName msg~target msg~arguments~makeString('L',',')) 188: msg~send --start 189: result = msg~result 190: end 191: else do 192: --.error~lineout('Event:' event 'is not a defined method in handler/listener:' l) 193: end 194: end 195:

If you feel inclined to make corrections, suggestions etc., please mail me any.
All content © Ruurd Idenburg, 2007–, except where marked otherwise. All rights reserved. This page is primarily for non-commercial use only. The Idenburg website records no personal information and sets no ‘cookies’. This site is hosted on a VPS(Virtual Private System) rented from Transip.nl, a Dutch company, falling under Dutch (privacy) laws (I think).

This page updated on by Ruurd Idenburg.