"{ NameSpace: NewInspector }"
Object subclass:#InspectorList
instanceVariableNames:'inspectedObject instanceNames instanceTypes selection'
classVariableNames:''
poolDictionaries:''
category:'Inspector'
!
!InspectorList class methodsFor:'instance creation'!
for:anObject
"create a new list for an instance
"
^ self new inspect:anObject
!
new
"create a new instance and set the inspected object to nil
"
^ self basicNew initialize.
! !
!InspectorList class methodsFor:'helpers'!
asString:aCollection
"converts any collection to a string seperated by spaces. If
the collection is empty or nil, nil is returned otherwise a
string.
"
|string|
aCollection isCollection ifTrue:[
aCollection isString ifTrue:[
string := aCollection
] ifFalse:[
string := aCollection asStringWith:Character space
from:1 to:(aCollection size)
compressTabs:true
final:nil
].
string := string withoutSeparators.
string notEmpty ifTrue:[
^ string
]
].
^ nil
! !
!InspectorList class methodsFor:'testing'!
isDirectory:anInstance
"returns true if the instance is a directory
"
|cls|
anInstance notNil ifTrue:[
cls := anInstance class.
cls == Character ifTrue:[ ^ false ].
cls == Symbol ifTrue:[ ^ false ].
cls == String ifTrue:[ ^ false ].
cls allInstVarNames notEmpty ifTrue:[
^ true
].
anInstance isVariable ifTrue:[
^ true
].
].
^ false
!
isTraceable:anInstance
"returns true if the instance could be traced or traped
"
|cls|
anInstance notNil ifTrue:[
cls := anInstance class.
^ ( cls ~~ True
and:[cls ~~ False
and:[cls ~~ SmallInteger]]
)
].
^ false.
! !
!InspectorList methodsFor:'accessing'!
includesSelf:aBoolean
"includes 'self' dependant on the boolean
"
(self includesSelf) ~~ aBoolean ifTrue:[
aBoolean ifTrue:[
instanceNames addFirst:'self'.
instanceTypes addFirst:#self.
selection notNil ifTrue:[selection := selection + 1]
ifFalse:[selection := 1]
] ifFalse:[
instanceNames removeFirst.
instanceTypes removeFirst.
selection isNil ifFalse:[
(selection := selection - 1) == 0 ifTrue:[
selection := nil
]
]
]
]
!
list
"returns self
"
^ self
!
size
"returns size of list
"
^ instanceNames size
!
update
"update list contents
"
|start stop size|
inspectedObject isVariable ifTrue:[
start := instanceNames findFirst:[:el|(el at:1) isDigit].
stop := instanceTypes size.
start == 0 ifTrue:[
size := stop + 10. "must be > 1: force a resize the first time"
] ifFalse:[
instanceTypes last ~~ #grow ifTrue:[size := stop]
ifFalse:[size := stop-1].
instanceTypes removeFromIndex:start toIndex:stop.
instanceNames removeFromIndex:start toIndex:stop.
].
self resizeTo:size.
]
! !
!InspectorList methodsFor:'accessing contents'!
inspectedObject
"returns current inspected object
"
^ inspectedObject
!
instanceNames
"returns list of instance names
"
^ instanceNames
!
instanceTypeAt:anIndex
"returns type assigned to the list entry (#directory #normal #self #grow)
In case of an invalid index nil is returned.
"
(anIndex isNil or:[anIndex > instanceTypes size]) ifFalse:[^ instanceTypes at:anIndex]
ifTrue:[^ nil].
!
instanceTypes
"returns list of types (#directory #normal #self #grow)
"
^ instanceTypes
!
instanceVarAt:anIndex
"returns the instnace variable assigned to the index or
nil in case of an invalid index.
"
|idx nm|
(anIndex isNil or:[anIndex > instanceTypes size]) ifFalse:[
nm := instanceNames at:anIndex.
(nm at:1) isDigit ifFalse:[
self includesSelf ifFalse:[
^ inspectedObject instVarAt:anIndex
].
anIndex == 1 ifFalse:[^ inspectedObject instVarAt:(anIndex-1)]
ifTrue:[^ inspectedObject]
].
^ inspectedObject basicAt:(Number readFrom:nm onError:0)
].
^ nil
! !
!InspectorList methodsFor:'initialization'!
initialize
"initialize instance attributes
"
super initialize.
instanceNames := OrderedCollection new.
instanceTypes := OrderedCollection new.
! !
!InspectorList methodsFor:'private'!
resizeTo:aNumber
"resize list to minimum aNumber
"
|lstVarId basicSize newLastId obj instSize|
(inspectedObject isVariable and:[self class isDirectory:inspectedObject]) ifFalse:[
^ self
].
instanceTypes size == 0 ifTrue:[
lstVarId := 0
] ifFalse:[
instSize := inspectedObject class instSize.
instanceTypes first == #self ifTrue:[
instSize := instSize + 1
].
instanceTypes last == #grow ifTrue:[
instanceNames removeLast. " .. "
instanceTypes removeLast. " #grow "
].
lstVarId := instanceTypes size - instSize.
].
(basicSize := inspectedObject basicSize) == lstVarId ifTrue:[
^ self
].
newLastId := (1 bitShift:((aNumber-1) highBit)) max:128.
(newLastId + 64) > basicSize ifTrue:[
newLastId := basicSize
].
[lstVarId ~~ newLastId] whileTrue:[
lstVarId := lstVarId + 1.
obj := inspectedObject basicAt:lstVarId.
(self class isDirectory:obj) ifTrue:[instanceTypes add:#directory]
ifFalse:[instanceTypes add:#normal].
instanceNames add:(lstVarId printString, ' ', obj class name printString).
].
lstVarId ~~ basicSize ifTrue:[
instanceNames add:'..'.
instanceTypes add:#grow
].
! !
!InspectorList methodsFor:'selections'!
selectedInstanceType
"returns type assigned to the selected list entry (#directory #normal #self #grow).
In case of no selection nil is returned.
"
^ self instanceTypeAt:selection
!
selectedInstanceVar
"returns current inspected instance variable or nil
"
^ self instanceVarAt:selection
!
selection
"returns current selection number or nil
"
^ selection
!
setSelection:aNrOrNil
"change current selection to a number or nil; may resize the lists
"
selection := aNrOrNil.
(selection isNil or:[instanceTypes size > selection]) ifFalse:[
self resizeTo:selection.
selection > instanceTypes size ifTrue:[
selection := nil
]
]
! !
!InspectorList methodsFor:'testing'!
includesSelf
"returns true if 'self' is included in the list
"
^ (instanceTypes notEmpty and:[instanceTypes first == #self])
!
isEmpty
"returns true if the list is empty
"
^ instanceNames isEmpty
!
notEmpty
"returns true if the list is not empty
"
^ instanceNames notEmpty
! !
!InspectorList methodsFor:'user interaction'!
accept:aText notifying:aView
"evaluating aText on the selected instance var; if an error occurs #Error
is returned otherwise the inspected object instance. On success the list
will be updated.
"
|text slNr value|
selection notNil ifTrue:[
text := self class asString:aText.
text notNil ifTrue:[
self includesSelf ifFalse:[slNr := selection]
ifTrue:[slNr := selection-1].
value := inspectedObject class evaluatorClass
evaluate:text
receiver:inspectedObject
notifying:aView.
slNr ~~ 0 ifTrue:[
(inspectedObject class isVariable) ifFalse:[
inspectedObject instVarAt:slNr put:value
] ifTrue:[
slNr <= (inspectedObject class instSize) ifTrue:[
inspectedObject instVarAt:slNr put:value
] ifFalse:[
slNr := slNr - inspectedObject class instSize.
inspectedObject basicAt:slNr put:value
]
]
].
inspectedObject changed.
self update.
^ inspectedObject
]
].
^ #Error
!
doIt:aCode notifying:aView
"evaluating aCode on the selected instance var; if an error occurs #Error
is returned otherwise the result returned from the evaluator. On success
the list will be updated.
"
|successFg result evaluator selInstVar code|
selInstVar := self selectedInstanceVar.
selInstVar notNil ifTrue:[
code := self class asString:aCode.
code notNil ifTrue:[
evaluator := selInstVar class evaluatorClass.
successFg := true.
evaluator notNil ifTrue:[
result := evaluator evaluate:code
in:nil
receiver:selInstVar
notifying:aView
logged:true
ifFail:[successFg := false].
successFg ifTrue:[
self update.
^ result
]
]
]
].
^ #Error.
!
inspect:anObject
"inspect a new instance; update contents
"
|varNamesSize|
selection := nil.
anObject == inspectedObject ifFalse:[
inspectedObject := anObject.
(self class isDirectory:inspectedObject) ifFalse:[
instanceNames := OrderedCollection new.
instanceTypes := OrderedCollection new.
] ifTrue:[
instanceNames := inspectedObject class allInstVarNames.
varNamesSize := instanceNames size.
instanceTypes := OrderedCollection new:varNamesSize.
1 to:varNamesSize do:[:i|
(self class isDirectory:(inspectedObject instVarAt:i)) ifTrue:[
instanceTypes add:#directory
] ifFalse:[
instanceTypes add:#normal
]
].
]
].
self update
! !
!InspectorList class methodsFor:'documentation'!
version
^ '$Header$'
! !