diff -r 8f8767c6f32f -r 9b705e31d38e UIHelpTool.st --- a/UIHelpTool.st Mon Mar 30 14:37:41 1998 +0200 +++ b/UIHelpTool.st Mon Mar 30 14:38:43 1998 +0200 @@ -12,9 +12,9 @@ -ApplicationModel subclass:#UIHelpTool - instanceVariableNames:'specClass dictionary dictionaries listSelection modified - modifiedHolder maxCharsPerLine' +ToolApplicationModel subclass:#UIHelpTool + instanceVariableNames:'specClass specSelector dictionary dictionaries listSelection + modifiedHolder maxCharsPerLine modified' classVariableNames:'' poolDictionaries:'' category:'Interface-UIPainter' @@ -49,7 +49,8 @@ is enabled, an active help bubble is shown at the widget's view. [author:] - Claus Atzkern + Claus Atzkern, eXept Software AG + Thomas Zwick, eXept Software AG " ! ! @@ -57,10 +58,20 @@ openOnClass:aClass " - UIHelpTool openOnClass:UIPainter + UIHelpTool openOnClass:self " - UIHelpTool open helpSpecFrom:aClass + UIHelpTool new openOnClass:aClass + +! ! + +!UIHelpTool class methodsFor:'accessing'! + +resourceType + "get the type of resource of the method generated by the Help Tool" + + ^#help + ! ! @@ -89,13 +100,19 @@ ^super helpSpec addPairsFrom:#( #addHelpTextKey -'Adds help text key.' +'Adds the help text key to the help spec.' #currentHelpTexts 'Selected help text key.' #deleteHelpTextKey -'Deletes the help text from the help spec.' +'Deletes the help text key from the help spec.' + +#fileLoad +'Opens a dialog for selecting and loading a help spec from a class.' + +#fileSave +'Saves current help spec.' #helpTextView 'Shows the help text.' @@ -135,84 +152,126 @@ #window: #(#WindowSpec #name: 'Help Tool' - #layout: #(#LayoutFrame 140 0 231 0 425 0 501 0) + #layout: #(#LayoutFrame 155 0 273 0 440 0 543 0) #label: 'Help Tool' #min: #(#Point 10 10) #max: #(#Point 1160 870) - #bounds: #(#Rectangle 140 231 426 502) + #bounds: #(#Rectangle 155 273 441 544) #usePreferredExtent: false ) #component: #(#SpecCollection #collection: #( - #(#SequenceViewSpec - #name: 'listOfHelpKeysView' - #layout: #(#LayoutFrame 3 0 2 0 -1 0.5 -1 0.5) - #activeHelpKey: #listOfHelpTexts - #tabable: true - #model: #listModel - #hasHorizontalScrollBar: true - #hasVerticalScrollBar: true - #miniScrollerHorizontal: true - #useIndex: false - #sequenceList: #listChannel - ) - #(#ActionButtonSpec - #name: 'AddButton' - #layout: #(#LayoutFrame 2 0.5 2 0 -1 0.67 26 0) - #activeHelpKey: #addHelpTextKey - #label: 'Add' - #tabable: true - #model: #add - ) - #(#ActionButtonSpec - #name: 'RemoveButton' - #layout: #(#LayoutFrame 1 0.67 2 0 -1 0.83 26 0) - #activeHelpKey: #removeHelpTextKey - #label: 'Remove' - #tabable: true - #model: #remove - ) - #(#ActionButtonSpec - #name: 'DeleteButton' - #layout: #(#LayoutFrame 1 0.83 2 0 -2 1 26 0) - #activeHelpKey: #deleteHelpTextKey - #label: 'Delete' - #tabable: true - #model: #delete - ) - #(#InputFieldSpec - #name: 'helpKeyInputField' - #layout: #(#LayoutFrame 1 0.5 29 0 -3 1 51 0) - #activeHelpKey: #currentHelpTexts - #tabable: true - #model: #listModel - #immediateAccept: false - ) - #(#SequenceViewSpec - #name: 'listOfHelpSpecClassesView' - #layout: #(#LayoutFrame 1 0.5 54 0 -3 1 -1 0.5) - #activeHelpKey: #listOfHelpSpecClasses - #tabable: true - #model: #selectionOfHelpSpecClass - #hasHorizontalScrollBar: true - #hasVerticalScrollBar: true - #miniScrollerHorizontal: true - #miniScrollerVertical: true - #valueChangeSelector: #helpSpecClassSelected - #useIndex: false - #sequenceList: #listOfHelpSpecClasses - ) - #(#TextEditorSpec - #name: 'helpTextView' - #layout: #(#LayoutFrame 3 0.0 1 0.5 -1 1.0 -3 1.0) - #activeHelpKey: #helpTextView - #tabable: true - #hasHorizontalScrollBar: true - #hasVerticalScrollBar: true - #miniScrollerHorizontal: true - #miniScrollerVertical: true + #(#VariableVerticalPanelSpec + #name: 'VariableVerticalPanel' + #layout: #(#LayoutFrame 0 0.0 0 0.0 0 1.0 0 1.0) + #component: + #(#SpecCollection + #collection: + #( + #(#VariableHorizontalPanelSpec + #name: 'VariableHorizontalPanel' + #component: + #(#SpecCollection + #collection: + #( + #(#SequenceViewSpec + #name: 'listOfHelpKeysView' + #activeHelpKey: #listOfHelpTexts + #tabable: true + #model: #listModel + #hasHorizontalScrollBar: true + #hasVerticalScrollBar: true + #miniScrollerHorizontal: true + #useIndex: false + #sequenceList: #listChannel + ) + #(#ViewSpec + #name: 'Box' + #component: + #(#SpecCollection + #collection: + #( + #(#InputFieldSpec + #name: 'helpKeyInputField' + #layout: #(#LayoutFrame 0 0.0 29 0 0 1.0 51 0) + #activeHelpKey: #currentHelpTexts + #tabable: true + #model: #listModel + #immediateAccept: false + ) + #(#SequenceViewSpec + #name: 'listOfHelpSpecClassesView' + #layout: #(#LayoutFrame 0 0.0 54 0 0 1.0 0 1.0) + #activeHelpKey: #listOfHelpSpecClasses + #tabable: true + #model: #selectionOfHelpSpecClass + #hasHorizontalScrollBar: true + #hasVerticalScrollBar: true + #miniScrollerHorizontal: true + #miniScrollerVertical: true + #valueChangeSelector: #helpSpecClassSelected + #useIndex: false + #sequenceList: #listOfHelpSpecClasses + ) + #(#HorizontalPanelViewSpec + #name: 'HorizontalPanel1' + #layout: #(#LayoutFrame 0 0.0 2 0 0 1.0 26 0) + #component: + #(#SpecCollection + #collection: + #( + #(#ActionButtonSpec + #name: 'AddButton' + #activeHelpKey: #addHelpTextKey + #label: 'Add' + #tabable: true + #model: #doAdd + #extent: #(#Point 44 24) + ) + #(#ActionButtonSpec + #name: 'RemoveButton' + #activeHelpKey: #removeHelpTextKey + #label: 'Remove' + #tabable: true + #model: #doRemove + #extent: #(#Point 45 24) + ) + #(#ActionButtonSpec + #name: 'DeleteButton' + #activeHelpKey: #deleteHelpTextKey + #label: 'Delete' + #tabable: true + #model: #doDelete + #extent: #(#Point 45 24) + ) + ) + ) + #horizontalLayout: #fit + #verticalLayout: #fit + #horizontalSpace: 3 + #verticalSpace: 3 + ) + ) + ) + ) + ) + ) + #handles: #(#Any 0.5 1.0) + ) + #(#TextEditorSpec + #name: 'helpTextView' + #activeHelpKey: #helpTextView + #tabable: true + #hasHorizontalScrollBar: true + #hasVerticalScrollBar: true + #miniScrollerHorizontal: true + #miniScrollerVertical: true + ) + ) + ) + #handles: #(#Any 0.5 1.0) ) ) ) @@ -239,11 +298,11 @@ #window: #(#WindowSpec #name: 'Help Tool' - #layout: #(#LayoutFrame 534 0 276 0 1033 0 675 0) + #layout: #(#LayoutFrame 191 0 334 0 660 0 663 0) #label: 'Help Tool' - #min: #(#Point 10 10) - #max: #(#Point 1160 870) - #bounds: #(#Rectangle 534 276 1034 676) + #min: #(#Point 300 300) + #max: #(#Point 1152 900) + #bounds: #(#Rectangle 191 334 661 664) #menu: #menu #usePreferredExtent: false ) @@ -252,10 +311,16 @@ #collection: #( #(#UISubSpecification - #name: 'UISubSpecification1' - #layout: #(#LayoutFrame 0 0.0 0 0.0 0 1.0 0 1.0) + #name: 'windowSpec' + #layout: #(#LayoutFrame 0 0.0 0 0.0 0 1.0 -26 1.0) #minorKey: #windowSpec ) + #(#UISubSpecification + #name: 'windowSpecForInfoBar' + #layout: #(#LayoutFrame 0 0 -24 1 0 1 0 1) + #majorKey: #ToolApplicationModel + #minorKey: #windowSpecForInfoBar + ) ) ) ) @@ -289,8 +354,9 @@ #( #(#MenuItem - #label: 'Reload' - #value: #doReload + #label: 'Load' + #value: #doLoad + #activeHelpKey: #fileLoad ) #(#MenuItem #label: '-' @@ -298,13 +364,7 @@ #(#MenuItem #label: 'Save' #value: #doSave - ) - #(#MenuItem - #label: '-' - ) - #(#MenuItem - #label: 'Define Class...' - #value: #doFromClass + #activeHelpKey: #fileSave ) #(#MenuItem #label: '-' @@ -312,6 +372,55 @@ #(#MenuItem #label: 'Exit' #value: #closeRequest + #activeHelpKey: #fileExit + ) + ) nil + nil + ) + ) + #(#MenuItem + #label: 'Edit' + #submenu: + #(#Menu + + #( + #(#MenuItem + #label: 'Add' + #value: #doAdd + #activeHelpKey: #addHelpTextKey + ) + #(#MenuItem + #label: '-' + ) + #(#MenuItem + #label: 'Delete' + #value: #doDelete + #activeHelpKey: #deleteHelpTextKey + ) + ) nil + nil + ) + ) + #(#MenuItem + #label: 'Help' + #startGroup: #right + #submenu: + #(#Menu + + #( + #(#MenuItem + #label: 'Documentation' + #value: #openHTMLDocument: + #activeHelpKey: #helpHelpTool + #argument: 'tools/uipainter/HelpTool.html' + ) + #(#MenuItem + #label: '-' + ) + #(#MenuItem + #label: 'Show Help Texts' + #activeHelpKey: #helpShowHelp + #indication: #showHelp: ) ) nil nil @@ -374,38 +483,6 @@ ! -helpSpecFrom:aClass - "read the help dictionary from aClass and find remaining classes - 'between' aClass and ApplicationModel - " - |help| - - modified := false. - specClass notNil - ifTrue: - [ - dictionary := Dictionary new. - dictionaries := Dictionary new. - ]. - specClass := self applicationClassAssociatedWith:aClass. - (specClass isClass and: [specClass isLoaded]) - ifTrue: - [ - (specClass class implements:#helpSpec) ifFalse:[ - dictionaries at: specClass name put: dictionary - ]. - self listOfHelpSpecClasses contents: (specClass withAllSuperclasses reverse collect: [:cls| cls name]). - (self listOfHelpSpecClasses includes: #ApplicationModel) - ifTrue: [self listOfHelpSpecClasses removeAll: (ApplicationModel withAllSuperclasses collect: [:cls| cls name])]. - self selectionOfHelpSpecClass value: specClass name. - (builder componentAt: #listOfHelpSpecClassesView) selection: - (self listOfHelpSpecClasses value indexOf: specClass name). - self helpSpecClassSelected. - ]. - - self updateList -! - modified "answer whether the help tool was modified " @@ -475,7 +552,7 @@ "get the value holder of the specClass and its superclasses which are subclasses of ApplicationModel " - |holder| + |holder| (holder := builder bindingAt:#listOfHelpSpecClasses) isNil ifTrue:[ builder aspectAt:#listOfHelpSpecClasses put: (holder := List new) ]. @@ -494,6 +571,47 @@ ! ! +!UIHelpTool methodsFor:'building'! + +buildFromClass:aClass + "read the help dictionary from aClass and find remaining classes + 'between' aClass and ApplicationModel + " + |help| + + modified := false. + specClass notNil + ifTrue: + [ + dictionary := Dictionary new. + dictionaries := Dictionary new. + ]. + specClass := self getHelpSpecClassFromClass:aClass. + (specClass isClass and: [specClass isLoaded]) + ifTrue: + [ + (specClass class implements:specSelector) ifFalse:[ + dictionaries at: specClass name put: dictionary + ]. + self listOfHelpSpecClasses contents: (specClass withAllSuperclasses reverse collect: [:cls| cls name]). + (self listOfHelpSpecClasses includes: #ApplicationModel) + ifTrue: [self listOfHelpSpecClasses removeAll: (ApplicationModel withAllSuperclasses collect: [:cls| cls name])]. + self selectionOfHelpSpecClass value: specClass name. + (builder componentAt: #listOfHelpSpecClassesView) selection: + (self listOfHelpSpecClasses value indexOf: specClass name). + self helpSpecClassSelected. + ]. + + self updateList +! + +buildFromClass: aClass andSelector: aSelector + + specSelector := aSelector. + self buildFromClass:aClass + +! ! + !UIHelpTool methodsFor:'callbacks'! helpSpecClassSelected @@ -528,17 +646,46 @@ ! ! +!UIHelpTool methodsFor:'help'! + +defaultInfoLabel + "get default label for the info bar" + + specClass isClass + ifTrue: + [ + (specClass class implements: specSelector) + ifFalse: + [ + ^specSelector isNil + ifTrue: [specClass name, ' >> ? (no selector defined)'] + ifFalse: [specClass name, ' >> ', specSelector, ' (not implemented)'] + ]. + ^specClass name, ' >> ', specSelector + ]. + ^'No class and selector defined.' + + + +! ! + !UIHelpTool methodsFor:'private'! -applicationClassAssociatedWith:aClass - "get application class keeping the associated help text or nil - " - |cls| +askForModification + "ask for modification" - ((cls := self resolveName:aClass) notNil and:[cls includesBehavior:UISpecification]) ifTrue:[ - ^UISpecificationTool + modified + ifTrue: + [ + ((YesNoBox title: 'List was modified!!') + noText:'Cancel'; + yesText:'Waste it and proceed'; + showAtPointer; + accepted) ifFalse: [^false]. + modified := false ]. - ^cls + ^true + ! @@ -569,8 +716,8 @@ " |helpSpecSuperClass superHelpSpecKeys helpSpec| - ((aClass class implements: #helpSpec) - and: [(helpSpecSuperClass := aClass allSuperclasses detect: [:cls| cls class implements: #helpSpec] ifNone: nil) notNil]) + ((aClass class implements: specSelector) + and: [(helpSpecSuperClass := aClass allSuperclasses detect: [:cls| cls class implements: specSelector] ifNone: nil) notNil]) ifTrue: [ superHelpSpecKeys := helpSpecSuperClass helpSpec keys. @@ -611,12 +758,25 @@ ! +getHelpSpecClassFromClass:aClass + "get application class keeping the associated help text or nil + " + |cls| + + ((cls := self resolveName:aClass) notNil and:[cls respondsTo: #helpSpecClass]) ifTrue:[ + ^cls helpSpecClass + ]. + ^cls + + +! + installHelpSpecOnClass:aClass "save the help dicts in aClass which is subclass of ApplicationModel" |cls src helpSpec| - cls := self applicationClassAssociatedWith:aClass. + cls := self getHelpSpecClassFromClass: aClass. cls isNil ifTrue:[ self information:'No application class defined!!'. @@ -634,12 +794,12 @@ ifTrue: [dictionaries at: aClass put: (self extractHelpSpecForClass: (Smalltalk at: aClass))] ifFalse: [dictionary size > 0 ifTrue: [dictionary] ifFalse: [Dictionary new]]]. - (cls class implements: #helpSpec) + (cls class implements: specSelector) ifTrue: [ |superclassHelpKeys implementedHelpSpec hasChanged| implementedHelpSpec := Dictionary new. - superclassHelpKeys := (cls superclass respondsTo: #helpSpec) + superclassHelpKeys := (cls superclass respondsTo: specSelector) ifTrue: [cls superclass helpSpec keys] ifFalse: [Array new]. @@ -660,13 +820,13 @@ ]. helpSpec isEmpty ifTrue:[ - ^(cls superclass respondsTo: #helpSpec) ifTrue: [cls class removeSelector: #helpSpec]. + ^(cls superclass respondsTo: specSelector) ifTrue: [cls class removeSelector: specSelector]. ]. src := '' writeStream. src nextPutAll: - 'helpSpec\' withCRs, + specSelector, '\' withCRs, (ResourceSpecEditor codeGenerationCommentForClass: UIHelpTool) withCRs, '\\' withCRs, ' "\' withCRs, @@ -675,7 +835,7 @@ - ^super helpSpec addPairsFrom:#( + ^super ', specSelector, ' addPairsFrom:#( '. @@ -706,20 +866,22 @@ " |cls helpSpecClasses| + cls := self getHelpSpecClassFromClass:aClass. + cls isNil ifTrue: [^self information:'No application class defined!!']. + modified ifFalse:[ + masterApplication isNil ifTrue: [self information:'Nothing was modified!!']. ^nil ]. - cls := aClass isClass ifTrue: [aClass name] ifFalse: [aClass]. - (helpSpecClasses := self listOfHelpSpecClasses value) notNil ifTrue: - [ - (helpSpecClasses includes: cls) ifFalse: [helpSpecClasses add: cls]. + [ + (helpSpecClasses includes: cls name) ifFalse: [helpSpecClasses add: cls name]. helpSpecClasses do: [:clsName| (self installHelpSpecOnClass: clsName) isNil ifTrue: [^modified := false]]. ] ifFalse: - [ + [ self installHelpSpecOnClass: cls ]. @@ -727,6 +889,27 @@ ! +resourceMessage: aString + "extract from aString the specClass and the specSelector" + + (aString notNil and: [self askForModification]) + ifTrue: + [ + |msg cls sel| + msg := aString asCollectionOfWords. + (msg size == 2 and: + [(cls := self resolveName:(msg at:1)) notNil]) + ifTrue: + [ + specClass := cls name. + specSelector := (msg at: 2) asSymbol. + ^true + ] + ]. + ^false + +! + updateList "update the list channel from dictionary " @@ -790,12 +973,7 @@ closeRequest "before closing the help tool, ask for permission " - (modified and:[self masterApplication isNil]) ifTrue:[ - (self confirm:'Exit without saving your modifications?') ifFalse:[ - ^ self - ] - ]. - ^super closeRequest + (self masterApplication isNil and:[self askForModification]) ifTrue:[super closeRequest] ! initialize @@ -803,16 +981,49 @@ " super initialize. + specSelector := #helpSpec. dictionary := Dictionary new. dictionaries := Dictionary new. modified := false. ! +loadFromMessage:aString + "load a spec from class and selector" + + (aString notNil and: [self askForModification]) + ifTrue: + [ + |msg cls sel| + msg := aString asCollectionOfWords. + (msg size == 2 and: + [(cls := self resolveName:(msg at:1)) notNil and: + [cls class implements: (sel := (msg at: 2) asSymbol)]]) + ifTrue: + [ + self buildFromClass: (specClass := cls name) andSelector: (specSelector := sel). + ^true + ] + ]. + ^false + +! + openInterface:aSymbol - "open interface + "do not open as stand alone " - super openInterface: #windowSpecForStandAlone + + +! + +openOnClass:aClass + "open the UIHelpTool on aClass + " + + super openInterface: #windowSpecForStandAlone. + self masterApplication isNil ifTrue: [(builder componentAt: #RemoveButton) beInvisible]. + builder window label: 'Help Tool'. + self buildFromClass: aClass ! ! !UIHelpTool methodsFor:'user actions'! @@ -842,54 +1053,61 @@ ] ! -add +doAdd "add help key " - self listModel value: (builder componentAt: #helpKeyInputField asSymbol) contents. - self accept + |helpKey| + (helpKey := (builder componentAt: #helpKeyInputField asSymbol) contents) size > 0 + ifTrue: + [ + self listModel value: helpKey. + self accept + ] + ifFalse: + [ + self warn: 'First define a help key!!' + ] ! -delete +doDelete "delete selected help key - " + " listSelection notNil ifTrue: [ dictionary removeKey: listSelection asSymbol ifAbsent: nil. - self remove. - + self doRemove. self updateList. - modified := true. modifiedHolder notNil ifTrue: [modifiedHolder value:true] ] + ifFalse: + [ + self warn: 'First select a help key!!' + ] ! -doFromClass - "setup new specification from a class accessed through to a dialog - " - |cls cls2 accepted| +doLoad + "open a Resource Selection Browser in order to get a resource message" - specClass notNil ifTrue:[cls := specClass name asValue] - ifFalse:[cls := '' asValue]. + self loadFromMessage: + (ResourceSelectionBrowser + request: 'Load ', self class resourceType asUppercaseFirst, ' Spec From Class' + onSuperclass: nil + andClass: specClass + andSelector: specSelector ? self class resourceType + withResourceTypes: (Array with: self class resourceType)) - [true] whileTrue:[ - accepted := - (DialogBox new - addTextLabel:'Class name:'; - addInputFieldOn:cls; - addAbortButton; - addOkButton; - open - ) accepted. - accepted ifFalse:[^ self]. - cls2 := self applicationClassAssociatedWith:cls value. +! - (cls2 notNil and: [cls2 respondsTo: #helpSpec]) ifTrue:[ - ^ self helpSpecFrom:cls2 - ]. - self warn:'No help spec found in class ', cls value asBoldText, '!!'. - ] +doNew + "reset the help tool + " + specClass := listSelection := nil. + self dictionary: nil. + self dictionaries: nil. + self listOfHelpSpecClasses removeAll. + modified := false. ! doReload @@ -906,28 +1124,26 @@ ! +doRemove + "remove selected help key + " + listSelection notNil + ifTrue: + [ + self listModel value: nil. + self updateList. + modifiedHolder notNil ifTrue: [modifiedHolder value:true] + ] + ifFalse: + [ + self warn: 'First select a help key!!' + ] +! + doSave "save the help dictionaries " self installHelpSpecsOnClass:specClass -! - -remove - "remove selected help key - " - self listModel value: nil. - self updateList. - modifiedHolder notNil ifTrue: [modifiedHolder value:true] -! - -reset - "reset the help tool - " - specClass := listSelection := nil. - self dictionary: nil. - self dictionaries: nil. - self listOfHelpSpecClasses removeAll. - modified := false. ! ! !UIHelpTool class methodsFor:'documentation'!