access mechanism for aspects
authorca
Wed, 25 Feb 1998 15:29:18 +0100
changeset 848 c0fab03dd225
parent 847 175a6578eb81
child 849 7e234a4ccaf6
access mechanism for aspects
UIBuilder.st
WinBuilder.st
WindowBuilder.st
--- a/UIBuilder.st	Sat Feb 21 15:32:35 1998 +0100
+++ b/UIBuilder.st	Wed Feb 25 15:29:18 1998 +0100
@@ -144,42 +144,6 @@
     isEditing := aState
 !
 
-menuAt:aKey
-    "Find a binding for the menu named aKey, either in the bindings 
-     or from the source"
-
-    | menu |
-
-    menu := self bindingAt:aKey.
-    menu isNil ifTrue:[
-        menu := self safelyPerform:#menuFor: with:aKey.
-        menu isNil ifTrue:[
-            menu := self safelyPerform:aKey
-        ].
-        menu := menu value.
-
-        (application notNil and:[menu notNil]) ifTrue:[
-            menu isArray ifTrue:[
-                menu := Menu new fromLiteralArrayEncoding:menu.
-                menu receiver:application.
-                ^ menu
-            ].
-            menu findGuiResourcesIn:application
-        ]
-    ].
-    ^ menu
-
-    "Modified: / 30.10.1997 / 20:37:14 / cg"
-!
-
-menuAt:aSymbol put:someMenuOrHolder
-    "add someMenuOrHolder as the binding for the menu named aSymbol to the bindings"
-
-    ^ self aspectAt:aSymbol put:someMenuOrHolder
-
-    "Modified: / 30.10.1997 / 20:32:51 / cg"
-!
-
 menuBar
     "return the value of the instance variable 'menuBar' (automatically generated)"
 
@@ -383,6 +347,6 @@
 !UIBuilder class methodsFor:'documentation'!
 
 version
-    ^ '$Header: /cvs/stx/stx/libview2/UIBuilder.st,v 1.32 1998-02-05 12:49:55 stefan Exp $'
+    ^ '$Header: /cvs/stx/stx/libview2/UIBuilder.st,v 1.33 1998-02-25 14:29:18 ca Exp $'
 ! !
 UIBuilder initialize!
--- a/WinBuilder.st	Sat Feb 21 15:32:35 1998 +0100
+++ b/WinBuilder.st	Wed Feb 25 15:29:18 1998 +0100
@@ -39,7 +39,16 @@
 "
     a no-op class, for systems which do not use the UIBuilder.
     Concrete subclasses know how to create a view (with components) from
-    some interface spec. 
+    some interface spec.
+
+    The order of the lookup sequence to access an aspect is defined:
+        application
+        application class
+        additional  class (applicationClass).
+
+    Methods to access any aspect are located in the category
+    'spec creation aspect fetch'.
+
     Currently, an experimantal version of UIBuilder exists,
     and more may be added in the future (for example, to parse different UI
     specs - thinking of motifs UIL specs, Windows DialogSpecs etc.).
@@ -156,6 +165,8 @@
     applicationClass := something.!
 
 aspectAt:aSymbol
+    "return the aspect for a symbol or nil.
+    "
     |b|
 
     aSymbol notNil ifTrue:[
@@ -179,16 +190,15 @@
             ] do:[
                 ^ application class aspectFor:aSymbol
             ].
-            Transcript showCR:'WindowBuilder: no aspect for ' , aSymbol storeString.
-            StopOnError == true ifTrue:[self halt].  "/ avoids debugger in end-user apps
-        ].
+            self aspectNotFound:aSymbol error:'no aspect for:'
+        ]
     ].
     ^ nil
-
-    "Modified: / 29.10.1997 / 17:26:16 / cg"
 !
 
 aspectAt:aSymbol put:aModel
+    "store an aspect identified by its symbol and its value
+    "
     bindings isNil ifTrue:[
         bindings := IdentityDictionary new
     ].
@@ -198,6 +208,8 @@
 !
 
 bindingAt:aSymbol
+    "return the binding for a symbol or nil
+    "
     bindings notNil ifTrue:[
         ^ bindings at:aSymbol ifAbsent:nil.
     ].
@@ -205,19 +217,27 @@
 !
 
 bindings
+    "return my bindings
+    "
     ^ bindings
 !
 
 bindings:aDictionary
+    "set bindings to a dictionary
+    "
     bindings := aDictionary
 !
 
 componentAt:name
+    "return a component identified by its name.
+    "
     namedComponents isNil ifTrue:[^ nil].
     ^ namedComponents at:name asSymbol ifAbsent:nil
 !
 
 componentAt:name put:aComponent
+    "store a component identified by its name.
+    "
     namedComponents isNil ifTrue:[
         namedComponents := IdentityDictionary new.
     ].
@@ -230,10 +250,14 @@
     componentCreationHook := something.!
 
 focusSequence 
+    "return my focus sequence
+    "
     ^ focusSequence
 !
 
 helpKeyFor:aComponent
+    "return the helpkey for a component or nil
+    "
     |v key|
 
     helpKeys isNil ifTrue:[^ nil].
@@ -248,7 +272,9 @@
 !
 
 helpKeyFor:aComponent put:aKey
-
+    "assign a key for a component which is used to access the help text
+     from the application.
+    "
     aKey isNil ifTrue:[
         helpKeys isNil ifFalse:[
             helpKeys removeKey:aComponent ifAbsent:nil
@@ -263,6 +289,8 @@
 !
 
 keyboardProcessor
+    "return my keyboard processor
+    "
     keyboardProcessor isNil ifTrue:[
         keyboardProcessor := KeyboardProcessor new    
     ].
@@ -272,7 +300,25 @@
     "Modified: 3.3.1997 / 18:32:27 / cg"
 !
 
+menuAt:aKey
+    "Find a binding for the menu named aKey, either in the bindings 
+     or from the source"
+
+    ^ self menuFor:aKey
+
+
+!
+
+menuAt:aSymbol put:someMenuOrHolder
+    "add someMenuOrHolder as the binding for the menu named aSymbol to the bindings"
+
+    ^ self aspectAt:aSymbol put:someMenuOrHolder
+
+!
+
 namedComponents
+    "return list of named components
+    "
     ^ namedComponents
 !
 
@@ -316,47 +362,29 @@
     ].
 
     majorKey isNil ifTrue:[
-        spec := self specificationFor:minorKey.
-        "/ try if application or applicationClass respond to minorKey
-        "/ (possible if not a subclass of ApplicationModel)
-        spec isNil ifTrue:[
-            application messageNotUnderstoodSignal handle:[:ex |
-                ex proceed.
-            ] do:[
-                application notNil ifTrue:[
-                    spec := application perform:minorKey.
-                ].
-                (spec isNil and:[applicationClass notNil]) ifTrue:[
-                    spec := applicationClass perform:minorKey.
-                ].
-            ].
-        ].
+        ^ self specificationFor:minorKey
+    ].
+
+    application notNil ifTrue:[
+        "/ look for class in applications namespace ...
+        cls := application resolveName:majorKey.
     ] ifFalse:[
-        application notNil ifTrue:[
-            "/ look for class in applications namespace ...
-            cls := application resolveName:majorKey.
-        ] ifFalse:[
-            "/ fallBack - use that global, if it exists
-            cls := Smalltalk at:majorKey.
-            cls isNil ifTrue:[
-                Transcript showCR:('WindowBuilder[warning]: missing application when fetching majorKey:' , majorKey).
-            ].
+        "/ fallBack - use that global, if it exists
+        cls := Smalltalk at:majorKey.
+        cls isNil ifTrue:[
+            Transcript showCR:('WindowBuilder[warning]: missing application when fetching majorKey:' , majorKey).
         ].
-        cls notNil ifTrue:[
-            Object messageNotUnderstoodSignal handle:[:ex |
-                ex proceed.
-            ] do:[
-                spec := cls specificationFor:minorKey.
-                spec isNil ifTrue:[
-                    spec := cls perform:minorKey.
-                ].
-            ].
-        ].                       
     ].
-    ^ spec
 
-    "Modified: / 27.1.1998 / 12:17:13 / cg"
-    "Modified: / 6.2.1998 / 12:31:45 / stefan"
+    cls notNil ifTrue:[
+        Object messageNotUnderstoodSignal handle:[:ex|] do:[
+            ^ cls specificationFor:minorKey
+        ].
+        Object messageNotUnderstoodSignal handle:[:ex|] do:[
+            ^ cls perform:minorKey.
+        ]
+    ].
+    ^ nil
 !
 
 subCanvasAt:majorKey at:minorKey put:aSpec
@@ -496,56 +524,100 @@
     "Modified: / 31.10.1997 / 18:39:30 / cg"
 ! !
 
+!WindowBuilder methodsFor:'error handling'!
+
+aspectNotFound:anAspect error:aString
+    "show error message on transcript
+    "
+    Transcript showCR:'WindowBuilder: '
+                     , aString
+                     , ' aspect: <'
+                     , anAspect storeString
+                     , '>'.
+
+    StopOnError == true ifTrue:[
+        self halt                       "/ avoids debugger in end-user apps
+    ].
+! !
+
 !WindowBuilder methodsFor:'message sending'!
 
-safelyPerform:aSelector
+safelyPerform:aSelector ifNone:aBlock
     "send the message aSelector to the application;
      the result returned from the send or nil is returned
     "
-    |res|
+    |cls|
 
-    aSelector isSymbol ifTrue:[
+    aSelector notNil ifTrue:[
         application notNil ifTrue:[
-            application messageNotUnderstoodSignal handle:[:ex |
-            ] do:[
-                (res := application perform:aSelector) notNil ifTrue:[^ res]
+            application messageNotUnderstoodSignal handle:[:ex|] do:[
+                ^ application perform:aSelector
+            ].
+            cls := application class.
+
+            cls messageNotUnderstoodSignal handle:[:ex|] do:[
+                ^ cls perform:aSelector
             ]
         ].
         applicationClass notNil ifTrue:[
-            applicationClass messageNotUnderstoodSignal handle:[:ex |
-            ] do:[
-                (res := applicationClass perform:aSelector) notNil ifTrue:[^ res]
+            applicationClass messageNotUnderstoodSignal handle:[:ex|] do:[
+                ^ applicationClass perform:aSelector
             ]
         ]
     ].
-  ^ nil
-
-    "Modified: / 5.2.1998 / 12:28:23 / stefan"
+  ^ aBlock value
 !
 
-safelyPerform:aSelector with:anArgument
+safelyPerform:aSelector with:anArgument ifNone:aBlock
     "send the one-arg-message aSelector to the application;
      the result returned from the send or nil is returned
     "
-    |res|
+    |cls|
 
-    aSelector isSymbol ifTrue:[
+    aSelector notNil ifTrue:[
         application notNil ifTrue:[
-            application messageNotUnderstoodSignal handle:[:ex |
-            ] do:[
-                (res := application perform:aSelector with:anArgument) notNil ifTrue:[^ res]
+            application messageNotUnderstoodSignal handle:[:ex|] do:[
+                ^ application perform:aSelector with:anArgument
+            ].
+            cls := application class.
+
+            cls messageNotUnderstoodSignal handle:[:ex|] do:[
+                ^ cls perform:aSelector with:anArgument
             ]
         ].
         applicationClass notNil ifTrue:[
-            applicationClass messageNotUnderstoodSignal handle:[:ex |
-            ] do:[
-                (res := applicationClass perform:aSelector with:anArgument) notNil ifTrue:[^ res]
+            applicationClass messageNotUnderstoodSignal handle:[:ex|] do:[
+                ^ applicationClass perform:aSelector with:anArgument
+            ].
+        ]
+    ].
+  ^ aBlock value
+!
+
+safelyPerform:aSelector with:arg1 with:arg2 ifNone:aBlock
+    "send the two-arg-message aSelector to the application;
+     the result returned from the send or nil is returned
+    "
+    |cls|
+
+    aSelector notNil ifTrue:[
+        application notNil ifTrue:[
+            application messageNotUnderstoodSignal handle:[:ex|] do:[
+                ^ application perform:aSelector with:arg1 with:arg2
+            ].
+            cls := application class.
+
+            cls messageNotUnderstoodSignal handle:[:ex|] do:[
+                ^ cls perform:aSelector with:arg1 with:arg2
             ]
         ].
+        applicationClass notNil ifTrue:[
+            applicationClass messageNotUnderstoodSignal handle:[:ex|] do:[
+                ^ applicationClass perform:aSelector with:arg1 with:arg2
+            ].
+        ]
     ].
-  ^ nil
-
-    "Modified: / 5.2.1998 / 12:28:54 / stefan"
+  ^ aBlock value
 ! !
 
 !WindowBuilder methodsFor:'spec creation aspect fetch'!
@@ -564,25 +636,9 @@
         b notNil ifTrue:[^ b].
     ].
 
-    application notNil ifTrue:[
-        Object messageNotUnderstoodSignal handle:[:ex |
-        ] do:[
-            ^ application actionFor:aKey
-        ]
-    ].
-    applicationClass notNil ifTrue:[
-        (applicationClass respondsTo:#actionFor:) ifTrue:[
-            ^ applicationClass actionFor:aKey
-        ]
-    ].
-
-    Transcript showCR:'WindowBuilder: no action for: ' , aKey storeString.
-    StopOnError == true ifTrue:[self halt].  "/ avoids debugger in end-user apps
-
-    ^ []
-
-    "Created: / 17.1.1997 / 21:08:22 / cg"
-    "Modified: / 28.10.1997 / 12:52:57 / cg"
+    ^ self safelyPerform:#actionFor:
+                    with:aKey
+                  ifNone:[ self aspectNotFound:aKey error:'no action for:'. [] ]
 !
 
 actionFor:aKey withValue:aValue
@@ -601,25 +657,10 @@
         b notNil ifTrue:[^ b].
     ].
 
-    application notNil ifTrue:[
-        Object messageNotUnderstoodSignal handle:[:ex |
-        ] do:[
-            ^ application actionFor:aKey withValue:aValue
-        ]
-    ].
-    applicationClass notNil ifTrue:[
-        (applicationClass respondsTo:#actionFor:withValue:) ifTrue:[
-            ^ applicationClass actionFor:aKey  withValue:aValue
-        ]
-    ].
-
-    Transcript showCR:'WindowBuilder: no action for: ' , aKey storeString.
-    StopOnError == true ifTrue:[self halt].  "/ avoids debugger in end-user apps
-
-    ^ [:dummy | ]
-
-    "Created: / 17.1.1997 / 21:08:22 / cg"
-    "Modified: / 28.10.1997 / 12:53:22 / cg"
+    ^ self safelyPerform:#actionFor:withValue:
+                    with:aKey
+                    with:aValue
+                  ifNone:[ self aspectNotFound:aKey error:'no action for:'. [:dummy |] ]
 !
 
 aspectFor:aKey
@@ -636,23 +677,9 @@
         b notNil ifTrue:[^ b].
     ].
 
-    application notNil ifTrue:[
-        Object messageNotUnderstoodSignal handle:[:ex |
-        ] do:[
-            ^ application aspectFor:aKey
-        ]
-    ].
-    applicationClass notNil ifTrue:[
-        Object messageNotUnderstoodSignal handle:[:ex |
-        ] do:[
-            ^ applicationClass aspectFor:aKey
-        ]
-    ].
-
-    ^ self aspectAt:aKey
-
-    "Created: / 17.1.1997 / 21:06:16 / cg"
-    "Modified: / 1.11.1997 / 13:40:24 / cg"
+    ^ self safelyPerform:#aspectFor:
+                    with:aKey
+                  ifNone:[ self aspectAt:aKey ]
 !
 
 componentFor:aKey
@@ -662,20 +689,9 @@
      finally the applications class is asked for a corresponding action.
      The returned object is typically a view."
 
-    |component|
-
-    application notNil ifTrue:[
-        component := application componentFor:aKey.
-        component notNil ifTrue:[^ component].
-    ].
-    applicationClass notNil ifTrue:[
-        (applicationClass respondsTo:#componentFor:) ifTrue:[
-            ^ applicationClass componentFor:aKey
-        ]
-    ].
-    ^ self aspectAt:aKey
-
-    "Modified: 20.6.1997 / 11:40:22 / cg"
+    ^ self safelyPerform:#componentFor:
+                    with:aKey
+                  ifNone:[ self aspectAt:aKey ]
 !
 
 labelFor:aKey
@@ -685,24 +701,9 @@
      finally the applications class is asked for a corresponding action.
      The returned object is typically a string."
 
-    application notNil ifTrue:[
-        Object messageNotUnderstoodSignal handle:[:ex |
-        ] do:[
-            ^ application labelFor:aKey
-        ]
-    ].
-    applicationClass notNil ifTrue:[
-        (applicationClass respondsTo:#labelFor:) ifTrue:[
-            ^ applicationClass labelFor:aKey
-        ]
-    ].
-
-"/    Transcript showCR:'WindowBuilder: no label for: ' , aKey storeString.
-"/    StopOnError == true ifTrue:[self halt].  "/ avoids debugger in end-user apps
-
-    ^ self aspectAt:aKey
-
-    "Modified: / 28.10.1997 / 12:54:10 / cg"
+    ^ self safelyPerform:#labelFor:
+                    with:aKey
+                  ifNone:[ self aspectAt:aKey ]
 !
 
 listFor:aKey
@@ -712,25 +713,39 @@
      finally the applications class is asked for a corresponding action.
      The returned object is typically a list."
 
-    application notNil ifTrue:[
-        Object messageNotUnderstoodSignal handle:[:ex |
-        ] do:[
-            ^ application listFor:aKey
+    ^ self safelyPerform:#listFor:
+                    with:aKey
+                  ifNone:[ self aspectAt:aKey ]
+!
+
+menuFor:aKey
+    "Find a binding for the menu named aKey, either in the bindings 
+     or from the source"
+
+    |menu|
+
+    (menu := self bindingAt:aKey) notNil ifTrue:[
+        ^ menu
+    ].
+
+    menu := self safelyPerform:#menuFor: with:aKey ifNone:[
+                    self safelyPerform:aKey ifNone:[
+                        self aspectNotFound:aKey error:'no menu for:'.
+                        nil
+                    ]
+                 ].
+
+    ((menu := menu value) notNil and:[application notNil]) ifTrue:[
+        menu isArray ifTrue:[
+            menu := Menu new fromLiteralArrayEncoding:menu.
+            menu receiver:application.
+        ] ifFalse:[
+            menu findGuiResourcesIn:application
         ]
     ].
-    applicationClass notNil ifTrue:[
-        (applicationClass respondsTo:#listFor:) ifTrue:[
-            ^ applicationClass listFor:aKey
-        ]
-    ].
+    ^ menu
 
-"/    Transcript showCR:'WindowBuilder: no list for: ' , aKey storeString.
-"/    StopOnError == true ifTrue:[self halt].  "/ avoids debugger in end-user apps
 
-    ^ self aspectAt:aKey
-
-    "Created: / 17.1.1997 / 21:08:45 / cg"
-    "Modified: / 28.10.1997 / 12:54:32 / cg"
 !
 
 specificationFor:aKey
@@ -740,29 +755,9 @@
      finally the applications class is asked for a corresponding interfaceSPec.
      The returned object is typically an interfaceSpec array."
 
-    |spec|
-
-    application notNil ifTrue:[
-        application messageNotUnderstoodSignal handle:[:ex |
-        ] do:[
-            spec := application specificationFor:aKey.
-        ].
-        spec notNil ifTrue:[^ spec].
-    ].
-    applicationClass notNil ifTrue:[
-        (applicationClass respondsTo:#specificationFor:) ifTrue:[
-            application messageNotUnderstoodSignal handle:[:ex |
-            ] do:[
-                spec := applicationClass specificationFor:aKey
-            ].
-            spec notNil ifTrue:[^ spec].
-        ]
-    ].
-    ^ self aspectAt:aKey
-
-    "Modified: / 20.6.1997 / 11:40:22 / cg"
-    "Created: / 5.2.1998 / 10:47:46 / stefan"
-    "Modified: / 5.2.1998 / 12:25:08 / stefan"
+    ^ self safelyPerform:#specificationFor:
+                    with:aKey
+                  ifNone:[ self aspectFor:aKey ]
 ! !
 
 !WindowBuilder methodsFor:'spec creation callbacks'!
@@ -983,5 +978,5 @@
 !WindowBuilder class methodsFor:'documentation'!
 
 version
-    ^ '$Header: /cvs/stx/stx/libview2/Attic/WinBuilder.st,v 1.59 1998-02-13 13:53:14 ca Exp $'
+    ^ '$Header: /cvs/stx/stx/libview2/Attic/WinBuilder.st,v 1.60 1998-02-25 14:28:55 ca Exp $'
 ! !
--- a/WindowBuilder.st	Sat Feb 21 15:32:35 1998 +0100
+++ b/WindowBuilder.st	Wed Feb 25 15:29:18 1998 +0100
@@ -39,7 +39,16 @@
 "
     a no-op class, for systems which do not use the UIBuilder.
     Concrete subclasses know how to create a view (with components) from
-    some interface spec. 
+    some interface spec.
+
+    The order of the lookup sequence to access an aspect is defined:
+        application
+        application class
+        additional  class (applicationClass).
+
+    Methods to access any aspect are located in the category
+    'spec creation aspect fetch'.
+
     Currently, an experimantal version of UIBuilder exists,
     and more may be added in the future (for example, to parse different UI
     specs - thinking of motifs UIL specs, Windows DialogSpecs etc.).
@@ -156,6 +165,8 @@
     applicationClass := something.!
 
 aspectAt:aSymbol
+    "return the aspect for a symbol or nil.
+    "
     |b|
 
     aSymbol notNil ifTrue:[
@@ -179,16 +190,15 @@
             ] do:[
                 ^ application class aspectFor:aSymbol
             ].
-            Transcript showCR:'WindowBuilder: no aspect for ' , aSymbol storeString.
-            StopOnError == true ifTrue:[self halt].  "/ avoids debugger in end-user apps
-        ].
+            self aspectNotFound:aSymbol error:'no aspect for:'
+        ]
     ].
     ^ nil
-
-    "Modified: / 29.10.1997 / 17:26:16 / cg"
 !
 
 aspectAt:aSymbol put:aModel
+    "store an aspect identified by its symbol and its value
+    "
     bindings isNil ifTrue:[
         bindings := IdentityDictionary new
     ].
@@ -198,6 +208,8 @@
 !
 
 bindingAt:aSymbol
+    "return the binding for a symbol or nil
+    "
     bindings notNil ifTrue:[
         ^ bindings at:aSymbol ifAbsent:nil.
     ].
@@ -205,19 +217,27 @@
 !
 
 bindings
+    "return my bindings
+    "
     ^ bindings
 !
 
 bindings:aDictionary
+    "set bindings to a dictionary
+    "
     bindings := aDictionary
 !
 
 componentAt:name
+    "return a component identified by its name.
+    "
     namedComponents isNil ifTrue:[^ nil].
     ^ namedComponents at:name asSymbol ifAbsent:nil
 !
 
 componentAt:name put:aComponent
+    "store a component identified by its name.
+    "
     namedComponents isNil ifTrue:[
         namedComponents := IdentityDictionary new.
     ].
@@ -230,10 +250,14 @@
     componentCreationHook := something.!
 
 focusSequence 
+    "return my focus sequence
+    "
     ^ focusSequence
 !
 
 helpKeyFor:aComponent
+    "return the helpkey for a component or nil
+    "
     |v key|
 
     helpKeys isNil ifTrue:[^ nil].
@@ -248,7 +272,9 @@
 !
 
 helpKeyFor:aComponent put:aKey
-
+    "assign a key for a component which is used to access the help text
+     from the application.
+    "
     aKey isNil ifTrue:[
         helpKeys isNil ifFalse:[
             helpKeys removeKey:aComponent ifAbsent:nil
@@ -263,6 +289,8 @@
 !
 
 keyboardProcessor
+    "return my keyboard processor
+    "
     keyboardProcessor isNil ifTrue:[
         keyboardProcessor := KeyboardProcessor new    
     ].
@@ -272,7 +300,25 @@
     "Modified: 3.3.1997 / 18:32:27 / cg"
 !
 
+menuAt:aKey
+    "Find a binding for the menu named aKey, either in the bindings 
+     or from the source"
+
+    ^ self menuFor:aKey
+
+
+!
+
+menuAt:aSymbol put:someMenuOrHolder
+    "add someMenuOrHolder as the binding for the menu named aSymbol to the bindings"
+
+    ^ self aspectAt:aSymbol put:someMenuOrHolder
+
+!
+
 namedComponents
+    "return list of named components
+    "
     ^ namedComponents
 !
 
@@ -316,47 +362,29 @@
     ].
 
     majorKey isNil ifTrue:[
-        spec := self specificationFor:minorKey.
-        "/ try if application or applicationClass respond to minorKey
-        "/ (possible if not a subclass of ApplicationModel)
-        spec isNil ifTrue:[
-            application messageNotUnderstoodSignal handle:[:ex |
-                ex proceed.
-            ] do:[
-                application notNil ifTrue:[
-                    spec := application perform:minorKey.
-                ].
-                (spec isNil and:[applicationClass notNil]) ifTrue:[
-                    spec := applicationClass perform:minorKey.
-                ].
-            ].
-        ].
+        ^ self specificationFor:minorKey
+    ].
+
+    application notNil ifTrue:[
+        "/ look for class in applications namespace ...
+        cls := application resolveName:majorKey.
     ] ifFalse:[
-        application notNil ifTrue:[
-            "/ look for class in applications namespace ...
-            cls := application resolveName:majorKey.
-        ] ifFalse:[
-            "/ fallBack - use that global, if it exists
-            cls := Smalltalk at:majorKey.
-            cls isNil ifTrue:[
-                Transcript showCR:('WindowBuilder[warning]: missing application when fetching majorKey:' , majorKey).
-            ].
+        "/ fallBack - use that global, if it exists
+        cls := Smalltalk at:majorKey.
+        cls isNil ifTrue:[
+            Transcript showCR:('WindowBuilder[warning]: missing application when fetching majorKey:' , majorKey).
         ].
-        cls notNil ifTrue:[
-            Object messageNotUnderstoodSignal handle:[:ex |
-                ex proceed.
-            ] do:[
-                spec := cls specificationFor:minorKey.
-                spec isNil ifTrue:[
-                    spec := cls perform:minorKey.
-                ].
-            ].
-        ].                       
     ].
-    ^ spec
 
-    "Modified: / 27.1.1998 / 12:17:13 / cg"
-    "Modified: / 6.2.1998 / 12:31:45 / stefan"
+    cls notNil ifTrue:[
+        Object messageNotUnderstoodSignal handle:[:ex|] do:[
+            ^ cls specificationFor:minorKey
+        ].
+        Object messageNotUnderstoodSignal handle:[:ex|] do:[
+            ^ cls perform:minorKey.
+        ]
+    ].
+    ^ nil
 !
 
 subCanvasAt:majorKey at:minorKey put:aSpec
@@ -496,56 +524,100 @@
     "Modified: / 31.10.1997 / 18:39:30 / cg"
 ! !
 
+!WindowBuilder methodsFor:'error handling'!
+
+aspectNotFound:anAspect error:aString
+    "show error message on transcript
+    "
+    Transcript showCR:'WindowBuilder: '
+                     , aString
+                     , ' aspect: <'
+                     , anAspect storeString
+                     , '>'.
+
+    StopOnError == true ifTrue:[
+        self halt                       "/ avoids debugger in end-user apps
+    ].
+! !
+
 !WindowBuilder methodsFor:'message sending'!
 
-safelyPerform:aSelector
+safelyPerform:aSelector ifNone:aBlock
     "send the message aSelector to the application;
      the result returned from the send or nil is returned
     "
-    |res|
+    |cls|
 
-    aSelector isSymbol ifTrue:[
+    aSelector notNil ifTrue:[
         application notNil ifTrue:[
-            application messageNotUnderstoodSignal handle:[:ex |
-            ] do:[
-                (res := application perform:aSelector) notNil ifTrue:[^ res]
+            application messageNotUnderstoodSignal handle:[:ex|] do:[
+                ^ application perform:aSelector
+            ].
+            cls := application class.
+
+            cls messageNotUnderstoodSignal handle:[:ex|] do:[
+                ^ cls perform:aSelector
             ]
         ].
         applicationClass notNil ifTrue:[
-            applicationClass messageNotUnderstoodSignal handle:[:ex |
-            ] do:[
-                (res := applicationClass perform:aSelector) notNil ifTrue:[^ res]
+            applicationClass messageNotUnderstoodSignal handle:[:ex|] do:[
+                ^ applicationClass perform:aSelector
             ]
         ]
     ].
-  ^ nil
-
-    "Modified: / 5.2.1998 / 12:28:23 / stefan"
+  ^ aBlock value
 !
 
-safelyPerform:aSelector with:anArgument
+safelyPerform:aSelector with:anArgument ifNone:aBlock
     "send the one-arg-message aSelector to the application;
      the result returned from the send or nil is returned
     "
-    |res|
+    |cls|
 
-    aSelector isSymbol ifTrue:[
+    aSelector notNil ifTrue:[
         application notNil ifTrue:[
-            application messageNotUnderstoodSignal handle:[:ex |
-            ] do:[
-                (res := application perform:aSelector with:anArgument) notNil ifTrue:[^ res]
+            application messageNotUnderstoodSignal handle:[:ex|] do:[
+                ^ application perform:aSelector with:anArgument
+            ].
+            cls := application class.
+
+            cls messageNotUnderstoodSignal handle:[:ex|] do:[
+                ^ cls perform:aSelector with:anArgument
             ]
         ].
         applicationClass notNil ifTrue:[
-            applicationClass messageNotUnderstoodSignal handle:[:ex |
-            ] do:[
-                (res := applicationClass perform:aSelector with:anArgument) notNil ifTrue:[^ res]
+            applicationClass messageNotUnderstoodSignal handle:[:ex|] do:[
+                ^ applicationClass perform:aSelector with:anArgument
+            ].
+        ]
+    ].
+  ^ aBlock value
+!
+
+safelyPerform:aSelector with:arg1 with:arg2 ifNone:aBlock
+    "send the two-arg-message aSelector to the application;
+     the result returned from the send or nil is returned
+    "
+    |cls|
+
+    aSelector notNil ifTrue:[
+        application notNil ifTrue:[
+            application messageNotUnderstoodSignal handle:[:ex|] do:[
+                ^ application perform:aSelector with:arg1 with:arg2
+            ].
+            cls := application class.
+
+            cls messageNotUnderstoodSignal handle:[:ex|] do:[
+                ^ cls perform:aSelector with:arg1 with:arg2
             ]
         ].
+        applicationClass notNil ifTrue:[
+            applicationClass messageNotUnderstoodSignal handle:[:ex|] do:[
+                ^ applicationClass perform:aSelector with:arg1 with:arg2
+            ].
+        ]
     ].
-  ^ nil
-
-    "Modified: / 5.2.1998 / 12:28:54 / stefan"
+  ^ aBlock value
 ! !
 
 !WindowBuilder methodsFor:'spec creation aspect fetch'!
@@ -564,25 +636,9 @@
         b notNil ifTrue:[^ b].
     ].
 
-    application notNil ifTrue:[
-        Object messageNotUnderstoodSignal handle:[:ex |
-        ] do:[
-            ^ application actionFor:aKey
-        ]
-    ].
-    applicationClass notNil ifTrue:[
-        (applicationClass respondsTo:#actionFor:) ifTrue:[
-            ^ applicationClass actionFor:aKey
-        ]
-    ].
-
-    Transcript showCR:'WindowBuilder: no action for: ' , aKey storeString.
-    StopOnError == true ifTrue:[self halt].  "/ avoids debugger in end-user apps
-
-    ^ []
-
-    "Created: / 17.1.1997 / 21:08:22 / cg"
-    "Modified: / 28.10.1997 / 12:52:57 / cg"
+    ^ self safelyPerform:#actionFor:
+                    with:aKey
+                  ifNone:[ self aspectNotFound:aKey error:'no action for:'. [] ]
 !
 
 actionFor:aKey withValue:aValue
@@ -601,25 +657,10 @@
         b notNil ifTrue:[^ b].
     ].
 
-    application notNil ifTrue:[
-        Object messageNotUnderstoodSignal handle:[:ex |
-        ] do:[
-            ^ application actionFor:aKey withValue:aValue
-        ]
-    ].
-    applicationClass notNil ifTrue:[
-        (applicationClass respondsTo:#actionFor:withValue:) ifTrue:[
-            ^ applicationClass actionFor:aKey  withValue:aValue
-        ]
-    ].
-
-    Transcript showCR:'WindowBuilder: no action for: ' , aKey storeString.
-    StopOnError == true ifTrue:[self halt].  "/ avoids debugger in end-user apps
-
-    ^ [:dummy | ]
-
-    "Created: / 17.1.1997 / 21:08:22 / cg"
-    "Modified: / 28.10.1997 / 12:53:22 / cg"
+    ^ self safelyPerform:#actionFor:withValue:
+                    with:aKey
+                    with:aValue
+                  ifNone:[ self aspectNotFound:aKey error:'no action for:'. [:dummy |] ]
 !
 
 aspectFor:aKey
@@ -636,23 +677,9 @@
         b notNil ifTrue:[^ b].
     ].
 
-    application notNil ifTrue:[
-        Object messageNotUnderstoodSignal handle:[:ex |
-        ] do:[
-            ^ application aspectFor:aKey
-        ]
-    ].
-    applicationClass notNil ifTrue:[
-        Object messageNotUnderstoodSignal handle:[:ex |
-        ] do:[
-            ^ applicationClass aspectFor:aKey
-        ]
-    ].
-
-    ^ self aspectAt:aKey
-
-    "Created: / 17.1.1997 / 21:06:16 / cg"
-    "Modified: / 1.11.1997 / 13:40:24 / cg"
+    ^ self safelyPerform:#aspectFor:
+                    with:aKey
+                  ifNone:[ self aspectAt:aKey ]
 !
 
 componentFor:aKey
@@ -662,20 +689,9 @@
      finally the applications class is asked for a corresponding action.
      The returned object is typically a view."
 
-    |component|
-
-    application notNil ifTrue:[
-        component := application componentFor:aKey.
-        component notNil ifTrue:[^ component].
-    ].
-    applicationClass notNil ifTrue:[
-        (applicationClass respondsTo:#componentFor:) ifTrue:[
-            ^ applicationClass componentFor:aKey
-        ]
-    ].
-    ^ self aspectAt:aKey
-
-    "Modified: 20.6.1997 / 11:40:22 / cg"
+    ^ self safelyPerform:#componentFor:
+                    with:aKey
+                  ifNone:[ self aspectAt:aKey ]
 !
 
 labelFor:aKey
@@ -685,24 +701,9 @@
      finally the applications class is asked for a corresponding action.
      The returned object is typically a string."
 
-    application notNil ifTrue:[
-        Object messageNotUnderstoodSignal handle:[:ex |
-        ] do:[
-            ^ application labelFor:aKey
-        ]
-    ].
-    applicationClass notNil ifTrue:[
-        (applicationClass respondsTo:#labelFor:) ifTrue:[
-            ^ applicationClass labelFor:aKey
-        ]
-    ].
-
-"/    Transcript showCR:'WindowBuilder: no label for: ' , aKey storeString.
-"/    StopOnError == true ifTrue:[self halt].  "/ avoids debugger in end-user apps
-
-    ^ self aspectAt:aKey
-
-    "Modified: / 28.10.1997 / 12:54:10 / cg"
+    ^ self safelyPerform:#labelFor:
+                    with:aKey
+                  ifNone:[ self aspectAt:aKey ]
 !
 
 listFor:aKey
@@ -712,25 +713,39 @@
      finally the applications class is asked for a corresponding action.
      The returned object is typically a list."
 
-    application notNil ifTrue:[
-        Object messageNotUnderstoodSignal handle:[:ex |
-        ] do:[
-            ^ application listFor:aKey
+    ^ self safelyPerform:#listFor:
+                    with:aKey
+                  ifNone:[ self aspectAt:aKey ]
+!
+
+menuFor:aKey
+    "Find a binding for the menu named aKey, either in the bindings 
+     or from the source"
+
+    |menu|
+
+    (menu := self bindingAt:aKey) notNil ifTrue:[
+        ^ menu
+    ].
+
+    menu := self safelyPerform:#menuFor: with:aKey ifNone:[
+                    self safelyPerform:aKey ifNone:[
+                        self aspectNotFound:aKey error:'no menu for:'.
+                        nil
+                    ]
+                 ].
+
+    ((menu := menu value) notNil and:[application notNil]) ifTrue:[
+        menu isArray ifTrue:[
+            menu := Menu new fromLiteralArrayEncoding:menu.
+            menu receiver:application.
+        ] ifFalse:[
+            menu findGuiResourcesIn:application
         ]
     ].
-    applicationClass notNil ifTrue:[
-        (applicationClass respondsTo:#listFor:) ifTrue:[
-            ^ applicationClass listFor:aKey
-        ]
-    ].
+    ^ menu
 
-"/    Transcript showCR:'WindowBuilder: no list for: ' , aKey storeString.
-"/    StopOnError == true ifTrue:[self halt].  "/ avoids debugger in end-user apps
 
-    ^ self aspectAt:aKey
-
-    "Created: / 17.1.1997 / 21:08:45 / cg"
-    "Modified: / 28.10.1997 / 12:54:32 / cg"
 !
 
 specificationFor:aKey
@@ -740,29 +755,9 @@
      finally the applications class is asked for a corresponding interfaceSPec.
      The returned object is typically an interfaceSpec array."
 
-    |spec|
-
-    application notNil ifTrue:[
-        application messageNotUnderstoodSignal handle:[:ex |
-        ] do:[
-            spec := application specificationFor:aKey.
-        ].
-        spec notNil ifTrue:[^ spec].
-    ].
-    applicationClass notNil ifTrue:[
-        (applicationClass respondsTo:#specificationFor:) ifTrue:[
-            application messageNotUnderstoodSignal handle:[:ex |
-            ] do:[
-                spec := applicationClass specificationFor:aKey
-            ].
-            spec notNil ifTrue:[^ spec].
-        ]
-    ].
-    ^ self aspectAt:aKey
-
-    "Modified: / 20.6.1997 / 11:40:22 / cg"
-    "Created: / 5.2.1998 / 10:47:46 / stefan"
-    "Modified: / 5.2.1998 / 12:25:08 / stefan"
+    ^ self safelyPerform:#specificationFor:
+                    with:aKey
+                  ifNone:[ self aspectFor:aKey ]
 ! !
 
 !WindowBuilder methodsFor:'spec creation callbacks'!
@@ -983,5 +978,5 @@
 !WindowBuilder class methodsFor:'documentation'!
 
 version
-    ^ '$Header: /cvs/stx/stx/libview2/WindowBuilder.st,v 1.59 1998-02-13 13:53:14 ca Exp $'
+    ^ '$Header: /cvs/stx/stx/libview2/WindowBuilder.st,v 1.60 1998-02-25 14:28:55 ca Exp $'
 ! !