james@1522: "{ Package: 'stx:libtool2' }" james@1522: james@1522: ApplicationModel subclass:#MethodFinderWindow james@1522: instanceVariableNames:'argumentsEditor messageAnswerEditor receiverEditor receiver james@1522: resultSelectors arg2BoxVisible arg1BoxVisible arg4BoxVisible james@1522: arg3BoxVisible argCountHolder argCountList argument1Editor james@1522: argument2Editor argument3Editor argument4Editor resultSelected cg@2891: lookAtResultEditor codeHolder searchProcess' james@1522: classVariableNames:'' james@1522: poolDictionaries:'' cg@1538: category:'Interface-MethodFinder' james@1522: ! james@1522: cg@1530: !MethodFinderWindow class methodsFor:'documentation'! cg@1530: cg@1530: documentation cg@1530: " cg@1531: [author:] cg@1531: ported from Squeak and GUI enhanced by James Hayes james@exept.de cg@1530: " cg@1530: ! ! james@1522: cg@1532: !MethodFinderWindow class methodsFor:'constants'! cg@1532: cg@2890: defaultIcon cg@2890: ^ ToolbarIconLibrary methodFinder24x24Icon cg@2890: cg@2890: "Created: / 01-06-2012 / 13:05:11 / cg" cg@2890: ! cg@2890: cg@1532: markerForImplementingClass cg@1532: ^ '=> '. cg@1532: ^ '*' cg@1532: cg@1532: "Created: / 13.11.2001 / 12:09:52 / cg" cg@1532: "Modified: / 13.11.2001 / 12:11:57 / cg" cg@1532: ! ! cg@1532: james@1522: !MethodFinderWindow class methodsFor:'interface specs'! james@1522: james@1522: windowSpec james@1522: "This resource specification was automatically generated james@1522: by the UIPainter of ST/X." james@1522: james@1522: "Do not manually edit this!! If it is corrupted, james@1522: the UIPainter may not be able to read the specification." james@1522: james@1522: " james@1522: UIPainter new openOnClass:MethodFinderWindow andSelector:#windowSpec james@1522: MethodFinderWindow new openInterface:#windowSpec james@1522: MethodFinderWindow open james@1522: " james@1522: james@1522: james@1522: james@1522: ^ cg@2886: #(FullSpec cg@2886: name: windowSpec cg@2886: window: cg@2886: (WindowSpec cg@2886: label: 'MethodFinder' cg@2886: name: 'MethodFinder' cg@2890: bounds: (Rectangle 0 0 798 595) cg@2886: menu: menu cg@2890: icon: defaultIcon james@1522: ) cg@2886: component: cg@2886: (SpecCollection cg@2886: collection: ( cg@2886: (VariableHorizontalPanelSpec cg@2886: name: 'VariableHorizontalPanel1' cg@2886: layout: (LayoutFrame 0 0.0 0 0.0 0 1.0 0 1.0) cg@2886: snapMode: both cg@2886: component: cg@2886: (SpecCollection cg@2886: collection: ( cg@2886: (ViewSpec cg@2886: name: 'LeftBox' cg@2886: level: 1 cg@2886: component: cg@2886: (SpecCollection cg@2886: collection: ( cg@2886: (ViewSpec cg@2886: name: 'ReceiverArgBox' cg@2887: layout: (LayoutFrame 0 0 0 0 0 1 -100 0.5) cg@2886: component: cg@2886: (SpecCollection cg@2886: collection: ( cg@2886: (LabelSpec cg@2886: label: 'Receiver' cg@2886: name: 'ReceiverLabel' cg@2886: layout: (LayoutFrame 0 0 0 0 0 0.34 24 0) cg@2886: translateLabel: true cg@2886: ) cg@2886: (ComboListSpec cg@2886: name: 'allowedArgments' cg@2886: layout: (LayoutFrame 0 0.34 1 0 0 0.64 23 0) cg@2886: model: argCountHolder cg@2886: comboList: argCountList cg@2886: useIndex: true cg@1530: ) cg@2886: (LabelSpec cg@2886: label: 'Answer' cg@2886: name: 'MessageAnswerLabel' cg@2886: layout: (LayoutFrame 0 0.64 0 0 0 1 24 0) cg@2886: translateLabel: true cg@1532: ) cg@2886: (HorizontalPanelViewSpec cg@2886: name: 'HorizontalPanel1' cg@2886: layout: (LayoutFrame 0 0 25 0 0 1 0 1) cg@2886: horizontalLayout: fit cg@2886: verticalLayout: fit cg@2886: horizontalSpace: 3 cg@2886: verticalSpace: 3 cg@2886: component: cg@2886: (SpecCollection cg@2886: collection: ( cg@2886: (WorkspaceSpec cg@2886: name: 'ReceiverEditor' cg@2886: tabable: true cg@2886: hasHorizontalScrollBar: true cg@2886: hasVerticalScrollBar: true cg@2886: miniScrollerHorizontal: true cg@2886: miniScrollerVertical: true cg@2886: autoHideScrollBars: true cg@2886: hasKeyboardFocusInitially: false cg@2890: extent: (Point 113 172) cg@2886: postBuildCallback: receiverWidgetCreated: cg@1532: ) cg@2886: (VerticalPanelViewSpec cg@2886: name: 'VerticalPanel1' cg@2886: horizontalLayout: fit cg@2886: verticalLayout: fit cg@2886: horizontalSpace: 3 cg@2886: verticalSpace: 3 cg@2886: component: cg@2886: (SpecCollection cg@2886: collection: ( cg@2886: (ViewSpec cg@2886: name: 'Box1' cg@2886: visibilityChannel: arg1BoxVisible cg@2886: component: cg@2886: (SpecCollection cg@2886: collection: ( cg@2886: (WorkspaceSpec cg@2886: name: 'Arg1Editor' cg@2886: layout: (LayoutFrame 0 0.0 0 0.0 0 1.0 0 1.0) cg@2886: tabable: true cg@2886: hasHorizontalScrollBar: true cg@2886: hasVerticalScrollBar: true cg@2886: miniScrollerHorizontal: true cg@2886: miniScrollerVertical: true cg@2886: autoHideScrollBars: true cg@2886: hasKeyboardFocusInitially: false cg@2886: postBuildCallback: argument1WidgetCreated: cg@1532: ) cg@1532: ) cg@1532: cg@1532: ) cg@2890: extent: (Point 114 55) cg@1532: ) cg@2886: (ViewSpec cg@2886: name: 'Box2' cg@2886: visibilityChannel: arg2BoxVisible cg@2886: component: cg@2886: (SpecCollection cg@2886: collection: ( cg@2886: (WorkspaceSpec cg@2886: name: 'TextEditor5' cg@2886: layout: (LayoutFrame 0 0.0 0 0.0 0 1.0 0 1.0) cg@2886: tabable: true cg@2886: hasHorizontalScrollBar: true cg@2886: hasVerticalScrollBar: true cg@2886: miniScrollerHorizontal: true cg@2886: miniScrollerVertical: true cg@2886: autoHideScrollBars: true cg@2886: hasKeyboardFocusInitially: false cg@2886: postBuildCallback: argument2WidgetCreated: cg@1532: ) cg@1532: ) cg@1532: cg@1532: ) cg@2890: extent: (Point 114 56) cg@1532: ) cg@2886: (ViewSpec cg@2886: name: 'Box3' cg@2886: visibilityChannel: arg3BoxVisible cg@2886: component: cg@2886: (SpecCollection cg@2886: collection: ( cg@2886: (WorkspaceSpec cg@2886: name: 'TextEditor6' cg@2886: layout: (LayoutFrame 0 0.0 0 0.0 0 1.0 0 1.0) cg@2886: tabable: true cg@2886: hasHorizontalScrollBar: true cg@2886: hasVerticalScrollBar: true cg@2886: miniScrollerHorizontal: true cg@2886: miniScrollerVertical: true cg@2886: autoHideScrollBars: true cg@2886: hasKeyboardFocusInitially: false cg@2886: postBuildCallback: argument3WidgetCreated: cg@1532: ) cg@1532: ) cg@1532: cg@1532: ) cg@2890: extent: (Point 114 55) cg@1530: ) cg@1530: ) cg@1530: cg@1530: ) cg@2890: extent: (Point 114 172) cg@1530: ) cg@2886: (WorkspaceSpec cg@2886: name: 'AnswerEditor' cg@2886: tabable: true cg@2886: hasHorizontalScrollBar: true cg@2886: hasVerticalScrollBar: true cg@2886: miniScrollerHorizontal: true cg@2886: miniScrollerVertical: true cg@2886: autoHideScrollBars: true cg@2886: hasKeyboardFocusInitially: false cg@2890: extent: (Point 114 172) cg@2886: postBuildCallback: messageAnswerWidgetCreated: james@1525: ) james@1525: ) james@1525: james@1525: ) james@1525: ) cg@1532: ) cg@1532: cg@1532: ) cg@1532: ) cg@2886: (ViewSpec cg@2886: name: 'ReceiverArgBoxActionBox' cg@2887: layout: (LayoutFrame 0 0 -98 0.5 0 1 -75 0.5) cg@2886: component: cg@2886: (SpecCollection cg@2886: collection: ( cg@2886: (ActionButtonSpec cg@2886: label: 'Clear' cg@2886: name: 'Button2' cg@2886: layout: (LayoutFrame 5 0 0 0 -5 0.5 0 1) cg@2886: translateLabel: true cg@2886: model: clear cg@1532: ) cg@2886: (ActionButtonSpec cg@2886: label: 'Search' cg@2886: name: 'Button1' cg@2886: layout: (LayoutFrame 5 0.5 0 0 -5 1 0 1) cg@2886: translateLabel: true cg@2886: tabable: true cg@2886: model: search james@1522: ) james@1522: ) james@1522: james@1522: ) james@1522: ) cg@2886: (ViewSpec cg@2886: name: 'MatchActionBox' cg@2887: layout: (LayoutFrame 0 0 -70 0.5 0 1 -20 0.5) cg@2886: component: cg@2886: (SpecCollection cg@2886: collection: ( cg@2886: (LabelSpec cg@2886: label: 'Selector Pattern:' cg@2886: name: 'Label1' cg@2887: layout: (LayoutFrame 0 0 0 0 0 0.5 25 0) cg@2886: translateLabel: true cg@2886: adjust: left cg@2886: ) cg@2886: (InputFieldSpec cg@2886: name: 'EntryField1' cg@2887: layout: (LayoutFrame 0 0 -25 1 0 0.5 -5 1) cg@2886: model: selectorPattern cg@2886: immediateAccept: true cg@2886: acceptOnReturn: true cg@2886: acceptOnTab: true cg@2886: acceptOnPointerLeave: true cg@2886: ) cg@2886: (ActionButtonSpec cg@2886: label: 'Search' cg@2886: name: 'Button4' cg@2886: layout: (LayoutFrame 5 0.5 -25 1 -5 1 0 1) cg@2886: translateLabel: true cg@2886: tabable: true cg@2886: model: searchPatternMatches cg@2886: ) cg@2886: ) cg@2886: cg@2886: ) cg@2886: ) cg@2886: (SequenceViewSpec cg@2886: name: 'ResultList' cg@2887: layout: (LayoutFrame 0 0 -15 0.5 0 1 0 1) cg@2886: hasHorizontalScrollBar: true cg@2886: hasVerticalScrollBar: true cg@2886: autoHideScrollBars: true cg@2886: valueChangeSelector: updateImplementorsOf: cg@2886: useIndex: true cg@2886: sequenceList: resultHolder cg@2886: ) cg@1530: ) cg@1530: cg@1530: ) cg@1530: ) cg@2886: (VariableVerticalPanelSpec cg@2886: name: 'VariableVerticalPanel1' cg@2886: component: cg@2886: (SpecCollection cg@2886: collection: ( cg@2886: (SequenceViewSpec cg@2886: name: 'List2' cg@2886: model: selectedClassOfResultHolder cg@2886: menu: implementorListMenu cg@2886: hasHorizontalScrollBar: true cg@2886: hasVerticalScrollBar: true cg@2886: autoHideScrollBars: true cg@2886: doubleClickSelector: openBrowserOn: cg@2886: valueChangeSelector: selectedClassOfResultHolderChanged cg@2886: useIndex: false cg@2886: sequenceList: classOfResultHolder cg@1530: ) cg@2886: (CodeViewSpec cg@2886: name: 'CodeView' cg@2886: model: codeHolder cg@2886: hasHorizontalScrollBar: true cg@2886: hasVerticalScrollBar: true cg@2886: autoHideScrollBars: true cg@2886: hasKeyboardFocusInitially: false cg@2886: postBuildCallback: sourceCodeWidgetCreated: james@1522: ) james@1522: ) james@1522: james@1522: ) cg@2886: handles: (Any 0.5 1.0) james@1522: ) james@1522: ) james@1522: james@1522: ) cg@2890: handles: (Any 0.443786982248521 1.0) james@1522: ) james@1522: ) james@1522: james@1522: ) james@1522: ) james@1522: ! ! james@1522: james@1525: !MethodFinderWindow class methodsFor:'menu specs'! james@1525: cg@1529: implementorListMenu cg@1529: "This resource specification was automatically generated cg@1529: by the MenuEditor of ST/X." cg@1529: cg@1529: "Do not manually edit this!! If it is corrupted, cg@1529: the MenuEditor may not be able to read the specification." cg@1529: cg@1529: " cg@1529: MenuEditor new openOnClass:MethodFinderWindow andSelector:#implementorListMenu cg@1529: (Menu new fromLiteralArrayEncoding:(MethodFinderWindow implementorListMenu)) startUp cg@1529: " cg@1529: cg@1529: cg@1529: cg@1529: ^ cg@1529: #(#Menu cg@1529: #( cg@1529: #(#MenuItem cg@1529: #label: 'Browse' cg@1529: #translateLabel: true cg@1529: #value: #openBrowserOnSelectedItem cg@1529: ) cg@1529: ) cg@1529: nil cg@1529: nil cg@1529: ) cg@1529: ! cg@1529: james@1525: menu james@1525: "This resource specification was automatically generated james@1525: by the MenuEditor of ST/X." james@1525: james@1525: "Do not manually edit this!! If it is corrupted, james@1525: the MenuEditor may not be able to read the specification." james@1525: james@1525: " james@1525: MenuEditor new openOnClass:MethodFinderWindow andSelector:#menu james@1525: (Menu new fromLiteralArrayEncoding:(MethodFinderWindow menu)) startUp james@1525: " james@1525: james@1525: james@1525: james@1525: ^ james@1525: #(#Menu james@1525: #( james@1525: #(#MenuItem james@1525: #label: '&File' james@1525: #activeHelpKey: #file james@1525: #submenu: james@1525: #(#Menu james@1525: #( james@1525: #(#MenuItem james@1525: #label: 'Exit' james@1525: #value: #closeRequest james@1525: #activeHelpKey: #fileExit james@1525: ) james@1525: ) james@1525: nil james@1525: nil james@1525: ) james@1525: ) james@1525: #(#MenuItem james@1525: #label: 'Help' james@1525: #startGroup: #right james@1525: #submenu: james@1525: #(#Menu james@1525: #( james@1525: #(#MenuItem james@1525: #label: 'Documentation' james@1525: #value: #openHTMLDocumentation james@1525: #activeHelpKey: #helpTutorial james@1525: ) james@1525: #(#MenuItem cg@1532: #label: 'About MethodFinder...' james@1525: #value: #openAboutThisApplication james@1525: #activeHelpKey: #aboutThisAppliaction james@1525: ) james@1525: ) james@1525: nil james@1525: nil james@1525: ) james@1525: ) james@1525: ) james@1525: nil james@1525: nil james@1525: ) cg@1532: cg@1532: "Modified: / 13.11.2001 / 12:36:39 / cg" james@1525: ! ! james@1525: james@1522: !MethodFinderWindow methodsFor:'accessing'! james@1522: james@1522: receiver james@1525: "Return a copy of the value of the instance variable 'receiver' " james@1522: james@1522: ^ receiver copy james@1522: ! ! james@1522: james@1522: !MethodFinderWindow methodsFor:'actions'! james@1522: james@1522: argumentEditorsContents james@1525: james@1525: "Determine how many text editors of the arguments are used and store the result james@1525: as argCounter. The result being the minimum between how many editors have james@1525: expressions in and how many are displayed. james@1525: james@1525: Add each argument string (key)and the evaluated version (value) to an Ordered Dictionary james@1525: from each of the text editors. james@1525: james@1525: Return the OrderedDictionary with the expressions from all the text editors. " james@1525: sr@2165: | tempArguments argCounter tempArgument1Editor tempArgument2Editor tempArgument3Editor james@1522: associationKey associationValue| james@1522: james@1522: argCounter:=0. james@1522: james@1522: tempArgument1Editor:= (self cleanInputs: argument1Editor contents). james@1522: tempArgument2Editor:= (self cleanInputs: argument2Editor contents). james@1522: tempArgument3Editor:= (self cleanInputs: argument3Editor contents). james@1522: james@1522: tempArgument1Editor = '' ifFalse:[argCounter:=argCounter +1]. james@1522: tempArgument2Editor = '' ifFalse:[argCounter:=argCounter +1]. james@1522: tempArgument3Editor = '' ifFalse:[argCounter:=argCounter +1]. james@1522: james@1522: james@1522: argCounter:= (argCounter min: (self argCountHolder value -1)). james@1522: tempArguments:= OrderedDictionary new:argCounter. james@1522: james@1522: (argCounter value >= 1) james@1522: ifTrue:[associationValue:= (Compiler evaluate: tempArgument1Editor). james@1522: ((self isExpression:tempArgument1Editor) or:[ associationValue isNil]) ifTrue:[ "looks if an expression is typed in" james@1522: associationKey:=associationValue printString] james@1522: ifFalse:[ james@1522: associationKey:=tempArgument1Editor]. james@1522: james@1522: tempArguments add: associationKey-> associationValue. james@1522: ]. james@1522: (argCounter value >= 2) james@1522: ifTrue:[ associationValue:= (Compiler evaluate: tempArgument2Editor). james@1522: (((self isExpression:tempArgument2Editor) or:[ associationValue isNil])) ifTrue:[ "looks if an expression is typed in" james@1522: associationKey:=associationValue printString] james@1522: ifFalse:[ james@1522: associationKey:=tempArgument2Editor]. james@1522: james@1522: tempArguments add: associationKey-> associationValue]. james@1522: james@1522: (argCounter value >= 3) james@1522: ifTrue:[ associationValue:= (Compiler evaluate: tempArgument3Editor). james@1522: ((self isExpression:tempArgument3Editor) or:[ associationValue isNil]) ifTrue:[ "looks if an expression is typed in" james@1522: associationKey:=associationValue printString] james@1522: ifFalse:[ james@1522: associationKey:=tempArgument3Editor]. james@1522: james@1522: tempArguments add: associationKey-> associationValue]. james@1522: james@1522: james@1522: ^tempArguments james@1522: ! james@1522: james@1522: clear james@1525: "Reset the contents of all the outputs. Return the receiver." james@1522: james@1522: receiverEditor contents:nil. james@1522: argument1Editor contents:nil. james@1522: argument2Editor contents:nil. james@1522: argument3Editor contents:nil. james@1522: messageAnswerEditor contents:nil. james@1522: self resultHolder value:nil. james@1525: self classOfResultHolder value: nil. cg@2730: codeHolder value:nil. james@1522: ! james@1522: cg@1532: extractClassAndSelectorFrom:anArgument cg@1532: "Opens browser on theArgument of a specific class. anArgument being a string with the cg@1532: Class and the selector upon which the browser is to be opened. Return the receiver." cg@1532: cg@1532: |aClass aSelector x theArgument marker| cg@1532: cg@1532: anArgument isNil ifTrue:[ cg@1532: ^ nil cg@1532: ]. cg@1532: marker := self class markerForImplementingClass. cg@1532: cg@1532: theArgument := anArgument string. cg@1532: (theArgument startsWith:marker) ifTrue:[ cg@1532: theArgument := theArgument copyFrom:marker size+1 cg@1532: ]. cg@1532: aClass := theArgument copyUpTo:(Character space). cg@1532: x := aClass size + 2. cg@1532: aSelector := theArgument copyFrom:x. cg@1532: aClass := Smalltalk classNamed:aClass. cg@2886: (aSelector startsWith:'class ') ifTrue:[ cg@2886: aSelector := aSelector copyFrom:'class 'size+1. cg@2886: aClass := aClass class. cg@2886: ]. cg@1532: ^ aClass -> aSelector asSymbol cg@1532: cg@1532: " cg@1532: MethodFinderWindow new extractClassAndSelectorFrom: '*SmallInteger +' cg@1532: MethodFinderWindow new extractClassAndSelectorFrom: 'String ,' cg@1532: MethodFinderWindow new extractClassAndSelectorFrom: 'Number detentBy:atMultiplesOf:snap:' cg@1532: cg@1532: cg@1532: " cg@1532: cg@2886: "Modified: / 27-04-2012 / 15:05:53 / cg" cg@1532: ! cg@1532: james@1522: isExpression: aString james@1525: "Return true or false depending on if the subString includes certain characters" james@1522: (aString includesSubString:': ') ifTrue:[^true]. james@1522: (aString includesSubString:'+') ifTrue:[^true]. james@1522: (aString includesSubString:'-') ifTrue:[^true]. james@1522: (aString includesSubString:'*') ifTrue:[^true]. james@1522: (aString includesSubString:'/') ifTrue:[^true]. james@1522: (aString includesSubString:'>') ifTrue:[^true]. james@1522: (aString includesSubString:'<') ifTrue:[^true]. james@1522: (aString includesSubString:' new') ifTrue:[^true]. james@1522: (aString includesSubString:'[') & (aString includesSubString:']') & (aString includesSubString:'.') james@1522: ifTrue:[^false]. james@1522: (aString includesSubString:'.') ifTrue:[^true]. james@1522: james@1522: ^false james@1522: ! james@1522: james@1522: messageAnswerEditorContents james@1525: "Return a cleaned up version of message answer taken from the messageAnswerEditor james@1525: as an association. The association has cleanedAnswerString as a key and the james@1525: compiledAnswer as value." james@1522: james@1522: | aCleanedAnswerString compiledAnswer | james@1522: james@1522: aCleanedAnswerString:=self cleanInputs: (messageAnswerEditor contents). james@1522: compiledAnswer:=Compiler evaluate: aCleanedAnswerString. james@1522: ((self isExpression:aCleanedAnswerString) or:[compiledAnswer isNil]) ifTrue:[ james@1522: aCleanedAnswerString:=compiledAnswer printString]. james@1522: james@1522: ^aCleanedAnswerString->compiledAnswer. james@1522: ! james@1522: james@1522: openBrowserOn:anArgument james@1522: "Opens browser on theArgument of a specific class. anArgument being a string with the james@1525: Class and the selector upon which the browser is to be opened. Return the receiver." james@1522: cg@1532: |classAndSelector| james@1522: cg@1532: classAndSelector := self extractClassAndSelectorFrom:anArgument. cg@1532: classAndSelector isNil ifTrue:[ james@1525: ^ self james@1522: ]. cg@2459: UserPreferences current systemBrowserClass cg@2459: openInClass:classAndSelector key cg@2459: selector:classAndSelector value james@1525: james@1525: " james@1525: MethodFinderWindow new openBrowserOn: '*SmallInteger +' james@1525: MethodFinderWindow new openBrowserOn: 'String ,' james@1525: MethodFinderWindow new openBrowserOn: 'Number detentBy:atMultiplesOf:snap:' james@1525: james@1525: james@1525: " cg@1532: cg@1532: "Modified: / 13.11.2001 / 12:46:17 / cg" james@1522: ! james@1522: cg@1529: openBrowserOnSelectedItem cg@1529: |sel| cg@1529: cg@1529: sel := self selectedClassOfResultHolder value. cg@1529: self openBrowserOn:sel cg@1532: cg@1532: "Modified: / 13.11.2001 / 12:47:39 / cg" cg@1529: ! cg@1529: james@1522: receiverEditorContents james@1525: "Return a cleaned up version of receiver taken from the receiverEditor james@1525: as an association. The association has aCleanedRecieverString as a key and the james@1525: compiledReceiver as value." james@1525: james@1522: | aCleanedRecieverString compiledReceiver | james@1522: james@1522: aCleanedRecieverString:=self cleanInputs: (receiverEditor contents). james@1522: james@1522: compiledReceiver:=Compiler evaluate: aCleanedRecieverString. james@1522: james@1522: ((self isExpression:aCleanedRecieverString) or:[compiledReceiver isNil]) ifTrue:[ james@1522: aCleanedRecieverString:=compiledReceiver printString]. james@1522: ^aCleanedRecieverString->compiledReceiver. james@1522: ! james@1522: james@1522: search james@1525: "Do a search based on the input in the various text editors. Return the receiver." james@1522: | tempReceiver tempAnswer tempArguments anArray resultArray receiverWithArgument mf| cg@1534: cg@1534: self resultHolder value: nil. "reset the result list" james@1522: self classOfResultHolder value: nil. "reset the implementorOf list" cg@1534: self codeHolder value: nil. "reset the source" james@1522: james@1522: tempArguments:=self argumentEditorsContents. james@1522: tempReceiver :=self receiverEditorContents . james@1522: tempAnswer:= self messageAnswerEditorContents. james@1522: james@1522: "self cleanInputRec:tempReceiver arg:tempArguments ans:tempAnswer." james@1522: james@1522: james@1522: anArray:=Array new:2. "creates an array which is to be used as input for the method finder." james@1522: james@1522: receiverWithArgument:=self mergReciever: (tempReceiver value) WithArgument: (tempArguments values). james@1522: james@1522: anArray at:1 put:receiverWithArgument; james@1522: at:2 put: tempAnswer value. james@1522: james@1522: "an array now holds the following array #(#(receiver argument) answer) or #(#(reciever) answer). which should james@1522: be suitable input for the method finder." cg@1534: self withCursor:Cursor execute do:[ cg@1534: mf:= MethodFinder new. cg@1534: resultArray:= mf load: anArray; findMessage. cg@1534: ]. james@1522: james@1522: ((resultArray at: 1 )includesSubString: 'no single') ifTrue:[ james@1522: self warn: (resultArray at: 1 ). james@1522: ^self james@1522: ]. james@1522: "the following then replaces data1 and data2 created by the method finder to the appropriate arguments" cg@2859: james@1522: resultArray keysAndValuesDo:[:key :value | | newValue | james@1522: newValue:= value replString: 'data1' withString:(tempReceiver key). james@1522: (tempArguments size) >= 1 ifTrue:[ james@1522: newValue:= newValue replString: 'data2' withString:(tempArguments keyAt:1)]. james@1522: james@1522: (tempArguments size) > 1 ifTrue:[ james@1522: newValue:= newValue replString: 'data3' withString:(tempArguments keyAt:2).]. james@1522: james@1522: (tempArguments size) > 2 ifTrue:[ james@1522: newValue:= newValue replString: 'data4' withString:(tempArguments keyAt:3).]. james@1522: cg@2859: (tempArguments size) > 3 ifTrue:[ self halt:'unimplemented'. ]. cg@1532: james@1522: james@1522: " newValue:= value replString: 'data3' withString:(self messageAnswer key). " james@1522: james@1522: newValue:=newValue, ' --> ', (tempAnswer key). cg@1532: newValue replaceAll:Character cr with:Character space. james@1522: james@1522: resultArray at: key put: newValue. james@1522: james@1522: ]. james@1522: james@1522: self resultHolder value: resultArray. james@1522: resultSelectors:= mf selectors. "used to find implementors so we do not have to " james@1522: receiver:=tempReceiver "search the string for the selector found. Stored as an ordered collection" cg@1532: cg@2859: "Modified: / 26-09-2011 / 12:42:28 / cg" cg@1532: ! cg@1532: cg@2891: searchPatternChanged cg@2891: "/ self searchPatternMatches cg@2891: self searchPatternMatchesInBackground cg@2891: cg@2891: "Created: / 01-06-2012 / 13:18:16 / cg" cg@2891: ! cg@2891: cg@2886: searchPatternMatches cg@2886: "Do a search based on the pattern match" cg@2886: cg@2886: | pattern list selectors counts| cg@2886: cg@2886: pattern := self selectorPattern value. cg@2886: cg@2886: self resultHolder value: nil. "reset the result list" cg@2886: self classOfResultHolder value: nil. "reset the implementorOf list" cg@2886: self codeHolder value: nil. "reset the source" cg@2886: cg@2886: self withCursor:Cursor execute do:[ cg@2889: pattern includesMatchCharacters ifFalse:[ cg@2889: pattern := '*',pattern,'*' cg@2889: ]. cg@2886: list := SystemBrowser findImplementorsMatching:pattern in:Smalltalk allClasses ignoreCase:true. cg@2886: ]. cg@2886: cg@2886: counts := IdentityDictionary new. cg@2886: selectors := IdentitySet new. cg@2886: cg@2886: list do:[:eachMethod | cg@2886: selectors add: eachMethod selector. cg@2886: (counts at:(eachMethod selector) ifAbsentPut:[0 asValue]) increment cg@2886: ]. cg@2886: cg@2886: resultSelectors := selectors asOrderedCollection sort. cg@2886: cg@2886: self resultHolder value: (resultSelectors collect:[:sel | sel,' --> ',(counts at:sel) value printString,' implementor(s)']). cg@2886: cg@2886: "Created: / 27-04-2012 / 14:46:35 / cg" cg@2886: ! cg@2886: cg@2891: searchPatternMatchesInBackground cg@2891: "Do a search based on the pattern match" cg@2891: cg@2891: | p pattern list| cg@2891: cg@2891: (p := searchProcess) notNil ifTrue:[ cg@2891: searchProcess := nil. cg@2891: p terminate. cg@2891: ]. cg@2891: cg@2891: searchProcess := cg@2891: [ cg@2891: pattern := self selectorPattern value. cg@2891: cg@2891: self withCursor:Cursor execute do:[ cg@2891: pattern includesMatchCharacters ifFalse:[ cg@2891: pattern := '*',pattern,'*' cg@2891: ]. cg@2891: list := SystemBrowser findImplementorsMatching:pattern in:Smalltalk allClasses ignoreCase:true. cg@2891: ]. cg@2891: self enqueueDelayedAction:[ self updateListAfterPatternSearch: list ] cg@2891: ] fork. cg@2891: cg@2891: "Created: / 01-06-2012 / 13:16:54 / cg" cg@2891: ! cg@2891: cg@1532: selectedClassOfResultHolderChanged cg@1532: |sel classAndSelector mthd| cg@1532: cg@1532: sel := self selectedClassOfResultHolder value. cg@1532: cg@1532: classAndSelector := self extractClassAndSelectorFrom:sel. cg@1532: classAndSelector isNil ifTrue:[ cg@1532: ^ self cg@1532: ]. cg@1532: mthd := classAndSelector key >> classAndSelector value. cg@1532: mthd notNil ifTrue:[ cg@1532: self withWaitCursorDo:[ cg@1532: self codeHolder value:mthd source cg@1532: ] cg@1532: ] ifFalse:[ cg@1532: self codeHolder value:nil cg@1532: ]. cg@1532: cg@1532: "Created: / 13.11.2001 / 12:43:43 / cg" cg@1532: "Modified: / 13.11.2001 / 12:48:56 / cg" james@1522: ! james@1522: james@1522: updateImplementorsOf:anInteger james@1525: "Request the implementors of the selected argument provided by aNumber. cg@2892: Return the receiver." cg@2892: cg@2892: |methods classList aNumber| james@1525: cg@2892: (anInteger isNil) ifTrue:[ cg@2892: ^ self cg@2892: ]. cg@2892: anInteger isNil ifTrue:[ cg@2892: aNumber := 1 cg@2892: ] ifFalse:[ cg@2892: aNumber := anInteger cg@2892: ]. cg@2892: methods := SystemBrowser cg@2892: findImplementorsOf:(resultSelectors at:aNumber) cg@2892: in:Smalltalk allClasses cg@2892: ignoreCase:false. cg@2892: classList := methods asOrderedCollection cg@2892: collect:[:m | m mclass name , ' ' , m selector ]. cg@2892: classList := (self markMatchingClasses:(resultSelectors at:aNumber) cg@2892: classesWithSelector:classList). cg@2892: self classOfResultHolder value:classList. cg@2892: classList size > 0 ifTrue:[ cg@2892: self selectedClassOfResultHolder value:(classList first). cg@2892: self selectedClassOfResultHolderChanged. cg@2892: ] ifFalse:[ cg@2892: self selectedClassOfResultHolder value:nil. cg@2892: ]. james@1522: cg@2892: "Modified (comment): / 24-06-2012 / 18:41:45 / cg" cg@2891: ! cg@2891: cg@2892: updateListAfterPatternSearch:list cg@2891: "Do a search based on the pattern match" cg@2892: cg@2892: |selectors counts firsts| cg@2891: cg@2892: self resultHolder value:nil. cg@2892: self classOfResultHolder value:nil. cg@2892: self codeHolder value:nil. cg@2891: counts := IdentityDictionary new. cg@2892: firsts := IdentityDictionary new. cg@2891: selectors := IdentitySet new. cg@2892: list do:[:eachMethod | cg@2892: selectors add:eachMethod selector. cg@2892: (counts at:(eachMethod selector) ifAbsentPut:[ 0 asValue ]) increment. cg@2892: firsts at:(eachMethod selector) ifAbsentPut:[ eachMethod mclass ]. cg@2892: ]. cg@2892: resultSelectors := selectors asOrderedCollection sort. cg@2892: self resultHolder value:(resultSelectors cg@2892: collect:[:sel | cg@2892: |cnt| cg@2891: cg@2892: cnt := (counts at:sel) value. cg@2892: cnt == 1 ifTrue:[ cg@2892: sel , ' --> ' , (firsts at:sel) name cg@2892: ] ifFalse:[ cg@2892: sel , ' --> ' , cnt printString , ' implementor(s)' cg@2892: ]. cg@2892: ]). cg@2891: cg@2891: "Created: / 01-06-2012 / 13:17:34 / cg" james@1522: ! ! james@1522: james@1522: !MethodFinderWindow methodsFor:'aspects'! james@1522: james@1522: arg1BoxVisible james@1525: "Determines if the box should be visble or not. Return true or false" james@1522: arg1BoxVisible isNil ifTrue:[ james@1522: arg1BoxVisible := BlockValue james@1522: with:[:vh | vh value >= 2 ] james@1522: argument:(self argCountHolder) james@1522: ]. james@1522: ^ arg1BoxVisible. james@1522: ! james@1522: james@1522: arg2BoxVisible james@1525: "Determines if the box should be visble or not. Return true or false" james@1522: arg2BoxVisible isNil ifTrue:[ james@1522: arg2BoxVisible := BlockValue james@1522: with:[:vh | vh value >= 3 ] james@1522: argument:(self argCountHolder) james@1522: ]. james@1522: ^ arg2BoxVisible. james@1522: ! james@1522: james@1522: arg3BoxVisible james@1525: "Determines if the box should be visble or not. Return true or false" james@1522: arg3BoxVisible isNil ifTrue:[ james@1522: arg3BoxVisible := BlockValue james@1522: with:[:vh | vh value >= 4 ] james@1522: argument:(self argCountHolder) james@1522: ]. james@1522: ^ arg3BoxVisible. james@1522: ! james@1522: james@1522: arg4BoxVisible james@1525: "Determines if the box should be visble or not. Return true or false" james@1522: arg4BoxVisible isNil ifTrue:[ james@1522: arg4BoxVisible := BlockValue james@1522: with:[:vh | vh value >= 5 ] james@1522: argument:(self argCountHolder) james@1522: ]. james@1522: ^ arg4BoxVisible. james@1522: ! james@1522: james@1522: argCountHolder james@1525: "Return the value of argCounterHolder which is initialized at 2." james@1522: argCountHolder isNil ifTrue:[ james@1522: argCountHolder := 2 asValue. james@1522: ]. james@1522: ^ argCountHolder. james@1522: ! james@1522: james@1522: argCountList james@1525: "Return the argCountList" james@1522: argCountList isNil ifTrue:[ james@1522: argCountList := #('0 arguments' '1 argument' '2 arguments' '3 arguments') asValue james@1522: ]. james@1522: ^ argCountList. james@1522: ! james@1522: james@1522: classOfResultHolder james@1525: "Return a valueHolder which contains a collection with the names of the james@1525: implementors of a specific message. " james@1522: james@1522: |holder| james@1522: (holder := builder bindingAt:#classOfResultHolder) isNil ifTrue:[ james@1525: holder := ValueHolder new. james@1525: builder aspectAt:#classOfResultHolder put:holder james@1522: ]. james@1522: ^ holder james@1522: ! james@1522: cg@1532: codeHolder cg@1532: codeHolder isNil ifTrue:[ cg@1532: codeHolder := '' asValue. cg@1532: ]. cg@1532: ^ codeHolder. cg@1532: cg@1532: "Created: / 13.11.2001 / 12:44:11 / cg" cg@1532: ! cg@1532: james@1522: resultHolder james@1525: "Return a value holder which contains the results of a search as a collection." james@1522: james@1522: |holder| james@1522: (holder := builder bindingAt:#resultHolder) isNil ifTrue:[ james@1525: holder := ValueHolder new. james@1525: builder aspectAt:#resultHolder put:holder. cg@2887: holder value:{ cg@2887: 'Please enter combination of' . cg@2887: ' ',('receiver, arg and result' allBold) . cg@2887: 'or a'. cg@2887: ' ',('selector search pattern' allBold) . cg@2890: 'into the above fields, then click on either ',('"search"' allBold),'-button.' cg@2887: } james@1522: ]. james@1522: ^ holder. cg@2886: cg@2890: "Modified: / 01-06-2012 / 13:06:02 / cg" cg@1529: ! cg@1529: cg@1529: selectedClassOfResultHolder cg@1529: "Return a valueHolder which contains the index of the selected result class cg@1529: (right list)" cg@1529: cg@1529: |holder| cg@1529: (holder := builder bindingAt:#selectedClassOfResultHolder) isNil ifTrue:[ cg@1529: holder := ValueHolder new. cg@1529: builder aspectAt:#selectedClassOfResultHolder put:holder cg@1529: ]. cg@1529: ^ holder cg@2886: ! cg@2886: cg@2886: selectorPattern cg@2886: |holder| cg@2886: (holder := builder bindingAt:#selectorPattern) isNil ifTrue:[ cg@2886: holder := ValueHolder new. cg@2886: builder aspectAt:#selectorPattern put:holder. cg@2891: holder onChangeSend:#searchPatternChanged to:self. cg@2886: ]. cg@2886: ^ holder cg@2886: cg@2886: "Created: / 27-04-2012 / 14:44:01 / cg" james@1522: ! ! james@1522: james@1522: !MethodFinderWindow methodsFor:'callBacks'! james@1522: james@1522: argument1WidgetCreated: aWidget james@1525: "Store the widget as an instance variable. Return the receiver" james@1525: james@1525: james@1522: argument1Editor := aWidget scrolledView. cg@1532: aWidget tabMeansNextField:true. cg@1532: cg@1532: "Modified: / 13.11.2001 / 12:21:41 / cg" james@1522: ! james@1522: james@1522: argument2WidgetCreated: aWidget james@1525: "Store the widget as an instance variable. Return the receiver" james@1525: james@1522: james@1522: argument2Editor := aWidget scrolledView. cg@1532: aWidget tabMeansNextField:true. cg@1532: cg@1532: "Modified: / 13.11.2001 / 12:21:45 / cg" james@1522: ! james@1522: james@1522: argument3WidgetCreated: aWidget james@1525: "Store the widget as an instance variable. Return the receiver" james@1525: james@1522: james@1522: argument3Editor := aWidget scrolledView. cg@1532: aWidget tabMeansNextField:true. cg@1532: cg@1532: "Modified: / 13.11.2001 / 12:21:49 / cg" james@1522: ! james@1522: james@1525: messageAnswerWidgetCreated: aWidget james@1525: "Store the widget as an instance variable. Return the receiver" james@1522: james@1525: messageAnswerEditor := aWidget scrolledView. cg@1532: aWidget tabMeansNextField:true. cg@1532: cg@1532: "Modified: / 13.11.2001 / 12:24:55 / cg" james@1522: ! james@1522: james@1525: openHTMLDocumentation james@1525: HTMLDocumentView openFullOnDocumentationFile:'tools/misc/TOP.html#METHODFINDER' james@1522: ! james@1522: james@1522: receiverWidgetCreated: aWidget james@1525: "Store the widget as an instance variable. Return the receiver" james@1522: james@1522: receiverEditor := aWidget scrolledView. cg@1532: aWidget tabMeansNextField:true. cg@1532: cg@1532: "Modified: / 13.11.2001 / 12:24:49 / cg" cg@1532: ! cg@1532: cg@1532: sourceCodeWidgetCreated: aWidget cg@1532: aWidget acceptAction:nil. cg@1532: aWidget readOnly:true cg@1532: cg@1532: "Created: / 13.11.2001 / 12:50:27 / cg" cg@1532: "Modified: / 13.11.2001 / 12:51:23 / cg" james@1522: ! ! james@1522: james@1522: !MethodFinderWindow methodsFor:'controlInput'! james@1522: james@1522: cleanInputs: aDirtyString james@1525: "Find and remove common mistakes made by the user. Return the james@1525: 'aStringToBeCleaned' variable" james@1522: | aStringToBeCleaned rs position| james@1522: james@1522: aStringToBeCleaned:=aDirtyString. james@1522: james@1522: (aStringToBeCleaned endsWith:(Character cr)) ifTrue:[ james@1522: aStringToBeCleaned:=aStringToBeCleaned copyFrom:1 to: (aStringToBeCleaned size -1).]. james@1522: aStringToBeCleaned:= aStringToBeCleaned withoutSeparators. james@1522: james@1522: james@1522: rs:=ReadStream on: aStringToBeCleaned. james@1522: [rs upToAll: '#true'. rs atEnd] whileFalse: [ james@1522: position:= rs position. james@1522: aStringToBeCleaned:=aStringToBeCleaned copyReplaceFrom: position to: position with: ''. "remove #" james@1522: rs:=ReadStream on: aStringToBeCleaned. james@1522: ]. james@1522: james@1522: rs:=ReadStream on: aStringToBeCleaned. james@1522: [rs upToAll: '#false'. rs atEnd] whileFalse: [ james@1522: position:= rs position. james@1522: aStringToBeCleaned:=aStringToBeCleaned copyReplaceFrom: position to: position with: ''. "remove #" james@1522: rs:=ReadStream on: aStringToBeCleaned. james@1522: rs:=ReadStream on: aStringToBeCleaned. ]. james@1522: james@1522: [rs upToAll: '#nil'. rs atEnd] whileFalse: [ james@1522: position:= rs position. james@1522: aStringToBeCleaned:=aStringToBeCleaned copyReplaceFrom: position to: position with: ''. "remove #" james@1522: rs:=ReadStream on: aStringToBeCleaned. ]. james@1522: ^aStringToBeCleaned james@1522: ! james@1522: james@1525: markMatchingClasses: aSelector classesWithSelector:anOrderedCollection james@1525: " Matches the class of the receiver with all the elements in anOrderedCollection james@1525: (which are classes with selectors). If a match is found it is marked with an asterisk. james@1525: The classes are then sorted so the the asterisk appears first. Return the james@1525: markedClassList." james@1522: sr@2165: | marker recClass unmarkedClassList markedClassList| james@1522: cg@1532: marker := self class markerForImplementingClass. cg@1532: cg@1532: recClass := receiver value class. james@1525: unmarkedClassList:=anOrderedCollection copy. james@1525: unmarkedClassList do: james@1525: [:classAndMethod | | class | james@1525: class:=Compiler evaluate: james@1525: ((ReadStream on: classAndMethod) upToAll: aSelector). cg@1532: "/ (recClass == class) cg@1532: (recClass whichClassImplements:aSelector) == class cg@1532: ifTrue: cg@1532: ["/ unmarkedClassList add: marker, classAndMethod. cg@1532: unmarkedClassList add: classAndMethod allBold. cg@1532: unmarkedClassList remove: classAndMethod. cg@1532: ]. cg@1532: ]. james@1522: james@1522: unmarkedClassList sort:[:a :b | |rawA rawB| cg@1532: rawA := a string. cg@1532: (rawA startsWith:marker) ifTrue:[rawA := rawA copyFrom:marker size+1]. cg@1532: rawB := b string. cg@1532: (rawB startsWith:marker) ifTrue:[rawB := rawB copyFrom:marker size+1]. cg@1532: rawA < rawB. ]. james@1525: markedClassList:= unmarkedClassList. james@1525: james@1525: ^markedClassList cg@1532: cg@1532: "Modified: / 13.11.2001 / 12:16:05 / cg" james@1522: ! james@1522: james@1522: mergReciever: aReceiver WithArgument: arguments james@1522: james@1525: "Puts the receiver and arguments into an array so it can be of a suitable input for the james@1525: MethodFinder. Return an array." james@1525: james@1522: | tempReceiver tempArguments receiverWithArgument| james@1522: james@1522: tempReceiver:= aReceiver. james@1522: tempArguments := arguments. james@1522: james@1522: (tempArguments isEmpty or:[(tempArguments) isNil]) james@1522: ifTrue:[ receiverWithArgument:=Array new:1."no argument" james@1522: receiverWithArgument at:1 put: tempReceiver. james@1522: ] james@1522: ifFalse:[ james@1522: (tempArguments size = 1) james@1522: ifTrue:[ receiverWithArgument:=Array new:2. james@1522: receiverWithArgument at:1 put: tempReceiver. james@1522: receiverWithArgument at:2 put: (tempArguments at:1) james@1522: ]. "a receiver with an argument" james@1522: james@1522: (tempArguments size = 2) james@1522: ifTrue:[ receiverWithArgument:=Array new:3. james@1522: receiverWithArgument at:1 put: tempReceiver. james@1522: (receiverWithArgument at:2 put: (tempArguments at:1)). james@1522: (receiverWithArgument at:3 put: (tempArguments at:2)) james@1522: ]. "a receiver with an argument" james@1522: (tempArguments size = 3) james@1522: ifTrue:[ receiverWithArgument:=Array new:4. james@1522: receiverWithArgument at:1 put: tempReceiver. james@1522: (receiverWithArgument at:2 put: (tempArguments at:1)). james@1522: (receiverWithArgument at:3 put: (tempArguments at:2)). james@1522: (receiverWithArgument at:4 put: (tempArguments at:3)). james@1522: james@1522: ]. "a receiver with an argument" james@1522: james@1522: ]. james@1522: ^receiverWithArgument james@1522: ! ! james@1522: cg@1532: !MethodFinderWindow methodsFor:'misc'! cg@1532: cg@1532: aboutThisApplicationText cg@1532: |msg| cg@1532: cg@1532: msg := super aboutThisApplicationText. cg@2412: msg := msg , '\\Ported from Squeak to ST/X by James Hayes (james@exept.de). cg@2412: Original written by Ted Kaehler, Scott Wallace and Dan Ingalls.'. cg@1532: ^msg withCRs. cg@1532: cg@1532: "Modified: / 13.11.2001 / 12:56:44 / cg" cg@1532: ! ! cg@1532: james@1522: !MethodFinderWindow class methodsFor:'documentation'! james@1522: james@1522: version james@1522: ^ '$Header$' cg@2730: ! cg@2730: cg@2730: version_CVS cg@2730: ^ '$Header$' james@1522: ! !