require 'Context/KeyMap' require 'Context/ExecutionProxy' module Context # The Context is the Presenter in the Model, View, Presentor (MVP) # model. It is an object that holds the logic for the UI # scenario that the application is currently in. Context is # an abstract class. # # A Context is made up of views, model objects and other sub-contexts. # One of the views should be a UI widget container that contains all # of the views for the Context. The concrete classes should define # the logic for the Context that is either called by enter() # or called from one of the contained views. # # Note that views are usually only instantiated in createViews, which # is called on enter(), not on Context creation. However, there is # no requirement for this. class Context attr_reader :parent, :mainView attr_writer :mainView # Create a new Context. Takes a Bridge that is used to # create the View s in using the correct namespace. def initialize(viewBridge) @parent = nil @mainView = nil @viewBridge = viewBridge @keyMap = KeyMap.new @entered = false end # Creates the views for the context. This method is called # automatically by enter() and probably should not be called otherwise. # This method should be overriden by the concrete class. It # should instantiate all the views and set @mainView def createViews # Nothing to do here end # This is intended to be private (how do I do that again?) # Just so that it doesn't create a view if it is already created def setupViews if @mainView.nil? createViews end end # Creates views and returns the main View. This is intended # to be used by test code where entering the context executes # code and you need to know what the view will be ahead of time. # I can think of no reason to use this in production code. def peekAtView setupViews @mainView end # Destroys the views for the context. This method is called # automatically by exit() and probably should not be called otherwise. # This method should be overriden by the concrete class. It # should destroy all the views and set @mainView to nil def destroyViews @mainView = nil end # Adds a view to the mainView # Since the mainView is intended to be a UI container that contains # all the views, this method is called by a sub-context's enter() # method to allow the parent's mainView to contain the sub-context's # views. def addView(view) @mainView.addView(view) unless @mainView.nil? end # Enters the Context. After it is called, the Context is then # active and can be interacted with. This method automatically # calls createViews() and adds the mainView to the parent's view. # # Usually this method will be overriden by the concrete class. # However, it should be careful to call super() in the appropriate # place. def enter(parent) @parent = parent if (@parent != nil) @entered = true setupViews parent.addView(@mainView) unless @mainView.nil? end end # Returns true if the context has been entered, but not exited. # Returns false if the context has never been entered, or if # it has been entered and then exited. def isEntered? @entered end # Exits the Context. After it is called, the context is no longer # active and can't be interacted with. This method automatically # removes the mainView from the parent's view and calls destroyViews(). # # Usually this method will be overriden by the concrete class. # However, it should be careful to call super() in the appropriate # place. def exit() @entered = false if !@parent.nil? && !@parent.mainView.nil? @parent.mainView.removeView(@mainView) unless @mainView.nil? end destroyViews end # Sets a binding for a key. # Whenever a key is pressed, the context is notified. This # sets up a binding between the key and the block passed in. # After that point, the block will be called everytime the # key is pressed. # # Warning: This key binding mechanism is likely to be # depracated, or at least heavily modified soon. def setKeyBinding(key, &binding) a = KeyAssignment.new(key, &binding) @keyMap.add(a) end # Returns the existing binding for a key. # # Warning: This key binding mechanism is likely to be # depracated, or at least heavily modified soon. def getKeyBinding(key) a = @keyMap.findKey(key) a.unless_nil.action end # Called by the view to indicated that a key has been pressed. # Runs the binding in the keymap, or returns nil if there # isn't one. # # Warning: This key binding mechanism is likely to be # depracated, or at least heavily modified soon. def notifyKey(view, key) @keyMap.unless_nil do press(key) end end end end