'From Cuis 1.0 of 28 November 2009 [latest update: #337] on 10 December 2009 at 11:28:48 pm'!
!classDefinition: #Inspector category: #'Tools-Inspector'!
StringHolder subclass: #Inspector
	instanceVariableNames: 'object selectionIndex timeOfLastListUpdate selectionUpdateTime context '
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Tools-Inspector'!
!classDefinition: #SetInspector category: #'Tools-Inspector'!
Inspector subclass: #SetInspector
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Tools-Inspector'!

!SetInspector commentStamp: '<historical>' prior: 0!
A verison of the Inspector specialized for inspecting Sets.  It displays the elements of the set like elements of an array.  Note that the indices, being phyical locations in the hash table, are not meaningful outside of the set.!

!classDefinition: #WeakSetInspector category: #'Tools-Inspector'!
SetInspector subclass: #WeakSetInspector
	instanceVariableNames: 'flagObject'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Tools-Inspector'!

!WeakSetInspector commentStamp: '<historical>' prior: 0!
A verison of the SetInspector specialized for inspecting WeakSets.  It knows about the flag object used to indicate empty locations in the hash table.!


!Object methodsFor: 'printing' stamp: 'jmv 12/10/2009 22:59'!
longPrintStringLimitedTo: aLimitValue
	"Answer a String whose characters are a description of the receiver."
	
	| str |
	str := String streamContents: [:aStream | self longPrintOn: aStream limitedTo: aLimitValue indent: 0].
	"Objects without inst vars should return something"
	^ str isEmpty ifTrue: [self printString, String cr] ifFalse: [str]! !


!Inspector methodsFor: 'accessing' stamp: 'sd 11/20/2005 21:27'!
context: ctxt
	"Set the context of inspection. Currently only used by my subclass ClosureEnvInspector. The inst var is here because we do primitiveChangeClassTo: between subclasses (see inspect:) between different subclasses, but also context could be used as a general concept in all inspectors"

	context := ctxt! !

!Inspector methodsFor: 'accessing' stamp: 'sd 11/20/2005 21:27'!
object: anObject 
	"Set anObject to be the object being inspected by the receiver."

	| oldIndex |
	anObject == object
		ifTrue: [self update]
		ifFalse:
			[oldIndex := selectionIndex <= 2 ifTrue: [selectionIndex] ifFalse: [0].
			self inspect: anObject.
			oldIndex := oldIndex min: self fieldList size.
			self changed: #inspectObject.
			oldIndex > 0
				ifTrue: [self toggleIndex: oldIndex].
			self changed: #fieldList.
			self changed: #contents]! !

!Inspector methodsFor: 'selecting' stamp: 'nice 11/8/2009 15:17'!
replaceSelectionValue: anObject 
	"The receiver has a list of variables of its inspected object. One of these 
	is selected. The value of the selected variable is set to the value, 
	anObject."
	| basicIndex si instVarIndex |
	selectionIndex <= 2 ifTrue: [
		self toggleIndex: (si := selectionIndex).  
		self toggleIndex: si.
		^ object].
	instVarIndex := selectionIndex - 2.
	instVarIndex > object class instSize
		ifFalse: [^ object instVarAt: instVarIndex put: anObject].
	object class isVariable or: [self error: 'Cannot replace selection'].
	basicIndex := selectionIndex - 2 - object class instSize.
	(object basicSize <= (self i1 + self i2)  or: [basicIndex <= self i1])
		ifTrue: [^object basicAt: basicIndex put: anObject]
		ifFalse: [^object basicAt: object basicSize - (self i1 + self i2) + basicIndex
					put: anObject]! !

!Inspector methodsFor: 'selecting' stamp: 'eem 5/21/2008 11:46'!
selectedSlotName

	^ self fieldList at: self selectionIndex ifAbsent: []! !

!Inspector methodsFor: 'selecting' stamp: 'sd 11/20/2005 21:27'!
selection
	"The receiver has a list of variables of its inspected object.
	One of these is selected. Answer the value of the selected variable."
	| basicIndex |
	selectionIndex = 0 ifTrue: [^ ''].
	selectionIndex = 1 ifTrue: [^ object].
	selectionIndex = 2 ifTrue: [^ object longPrintStringLimitedTo: 20000].
	(selectionIndex - 2) <= object class instSize
		ifTrue: [^ object instVarAt: selectionIndex - 2].
	basicIndex := selectionIndex - 2 - object class instSize.
	(object basicSize <= (self i1 + self i2)  or: [basicIndex <= self i1])
		ifTrue: [^ object basicAt: basicIndex]
		ifFalse: [^ object basicAt: object basicSize - (self i1 + self i2) + basicIndex]! !

!Inspector methodsFor: 'selecting' stamp: 'apb 8/20/2004 22:03'!
selectionPrintString
	| text |
	selectionUpdateTime := [text := [self selection printStringLimitedTo: 5000]
						on: Error
						do: [text := self printStringErrorText.
							text
								addAttribute: TextColor red
								from: 1
								to: text size.
							text]] timeToRun.
	^ text! !

!Inspector methodsFor: 'menu commands' stamp: 'sd 11/20/2005 21:27'!
chasePointers
	| selected  saved |
	self selectionIndex == 0 ifTrue: [^ self changed: #flash].
	selected := self selection.
	saved := self object.
	[self object: nil.
	(Smalltalk includesKey: #PointerFinder)
		ifTrue: [PointerFinder on: selected]
		ifFalse: [self inspectPointers]]
		ensure: [self object: saved]! !

!Inspector methodsFor: 'initialize-release' stamp: 'sd 11/20/2005 21:27'!
initialize
	
	selectionIndex := 0.
	super initialize! !

!Inspector methodsFor: 'initialize-release' stamp: 'sd 11/20/2005 21:27'!
inspect: anObject 
	"Initialize the receiver so that it is inspecting anObject. There is no current selection.
	
	Normally the receiver will be of the correct class (as defined by anObject inspectorClass),
	because it will have just been created by sedning inspect to anObject.   However, the
	debugger uses two embedded inspectors, which are re-targetted on the current receiver
	each time the stack frame changes.  The left-hand inspector in the debugger has its
	class changed by the code here.  Care should be taken if this method is overridden to
	ensure that the overriding code calls 'super inspect: anObject', or otherwise ensures that 
	the class of these embedded inspectors are changed back."

	| c |
	c := anObject inspectorClass.
	(self class ~= c and: [self class format = c format]) ifTrue: [
		self primitiveChangeClassTo: c basicNew].
	
	"Set 'object' before sending the initialize message, because some implementations
	of initialize (e.g., in DictionaryInspector) require 'object' to be non-nil."
	
	object := anObject. 
	self initialize! !

!Inspector methodsFor: 'object fileIn' stamp: 'sd 11/20/2005 21:27'!
convertToCurrentVersion: varDict refStream: smartRefStrm
	
	timeOfLastListUpdate ifNil: [timeOfLastListUpdate := 0].
	^super convertToCurrentVersion: varDict refStream: smartRefStrm.

! !

!Inspector methodsFor: 'private' stamp: 'sd 11/20/2005 21:27'!
printStringErrorText
	| nm |
	nm := self selectionIndex < 3
					ifTrue: ['self']
					ifFalse: [self selectedSlotName].
	^ ('<error in printString: evaluate "' , nm , ' printString" to debug>') asText.! !

!Inspector methodsFor: 'toolbuilder' stamp: 'ar 10/4/2009 21:16'!
buildCodePaneWith: builder
	| textSpec |
	textSpec := builder pluggableTextSpec new.
	textSpec 
		model: self;
		getText: #trash; 
		setText: #trash:; 
		selection: #contentsSelection; 
		menu: #codePaneMenu:shifted:;
		askBeforeDiscardingEdits: false.
	^textSpec! !

!Inspector methodsFor: 'toolbuilder' stamp: 'ar 8/8/2009 11:47'!
buildFieldListWith: builder

	| listSpec |
	listSpec := builder pluggableListSpec new.
	listSpec 
		model: self;
		list: #fieldList; 
		getIndex: #selectionIndex; 
		setIndex: #toggleIndex:; 
		menu: #fieldListMenu:; 
		keyPress: #inspectorKey:from:.
	^listSpec! !

!Inspector methodsFor: 'toolbuilder' stamp: 'ar 8/8/2009 11:47'!
buildValuePaneWith: builder
	| textSpec |
	textSpec := builder pluggableTextSpec new.
	textSpec 
		model: self;
		getText: #contents; 
		setText: #accept:; 
		selection: #contentsSelection; 
		menu: #codePaneMenu:shifted:.
	^textSpec! !

!Inspector methodsFor: 'toolbuilder' stamp: 'ar 8/8/2009 11:50'!
buildWith: builder
	"Inspector openOn: SystemOrganization"
	| windowSpec |
	windowSpec := self buildWindowWith: builder specs: {
		(0@0 corner: 0.3@0.7)  -> [self buildFieldListWith: builder].
		(0.3@0.0corner: 1@0.7) -> [self buildValuePaneWith: builder].
		(0.0@0.7corner: 1@1) -> [self buildCodePaneWith: builder].
	}.
	^builder build: windowSpec! !

!Inspector methodsFor: 'stepping' stamp: 'sd 11/20/2005 21:27'!
stepAt: millisecondClockValue in: aWindow
	| newText |

	(Preferences smartUpdating and: [(millisecondClockValue - self timeOfLastListUpdate) > 8000]) "Not more often than once every 8 seconds"
		ifTrue:
			[self updateListsAndCodeIn: aWindow.
			timeOfLastListUpdate := millisecondClockValue].

	newText := self contentsIsString
		ifTrue: [self selection]
		ifFalse: ["keep it short to reduce time to compute it"
			self selectionPrintString ].
	newText = contents ifFalse:
		[contents := newText.
		self changed: #contents]! !


!DictionaryInspector methodsFor: 'accessing' stamp: 'apb 8/20/2004 23:06'!
fieldList
	^ self baseFieldList
		, (keyArray collect: [:key | key printString])! !

!DictionaryInspector methodsFor: 'selecting' stamp: 'sd 11/20/2005 21:27'!
addEntry: aKey
	object at: aKey put: nil.
	self calculateKeyArray.
	selectionIndex := self numberOfFixedFields + (keyArray indexOf: aKey).
	self changed: #inspectObject.
	self changed: #selectionIndex.
	self changed: #fieldList.
	self update! !

!DictionaryInspector methodsFor: 'selecting' stamp: 'sd 11/20/2005 21:27'!
refreshView
	| i |
	i := selectionIndex.
	self calculateKeyArray.
	selectionIndex := i.
	self changed: #fieldList.
	self changed: #contents.! !

!DictionaryInspector methodsFor: 'selecting' stamp: 'apb 8/20/2004 22:37'!
replaceSelectionValue: anObject 
	selectionIndex <= self numberOfFixedFields
		ifTrue: [^ super replaceSelectionValue: anObject].
	^ object
		at: (keyArray at: selectionIndex - self numberOfFixedFields)
		put: anObject! !

!DictionaryInspector methodsFor: 'selecting' stamp: 'apb 8/20/2004 21:55'!
selection

	selectionIndex <= (self numberOfFixedFields) ifTrue: [^ super selection].
	^ object at: (keyArray at: selectionIndex - self numberOfFixedFields) ifAbsent:[nil]! !

!DictionaryInspector methodsFor: 'menu' stamp: 'jmv 12/10/2009 23:07'!
addEntry
	| newKey aKey |

	newKey _ FillInTheBlank request:
'Enter new key, then type RETURN.
(Expression will be evaluated for value.)
Examples:  #Fred    ''a string''   3+4'.
	aKey _ Smalltalk actualCompilerClass evaluate: newKey.
	object at: aKey put: nil.
	self calculateKeyArray.
	selectionIndex _ self numberOfFixedFields + (keyArray indexOf: aKey).
	self changed: #inspectObject.
	self changed: #selectionIndex.
	self changed: #fieldList.
	self update! !

!DictionaryInspector methodsFor: 'menu' stamp: 'apb 8/20/2004 21:19'!
copyName
	"Copy the name of the current variable, so the user can paste it into the 
	window below and work with is. If collection, do (xxx at: 1)."
	| sel |
	self selectionIndex <= self numberOfFixedFields
		ifTrue: [super copyName]
		ifFalse: [sel := String streamContents: [:strm | 
							strm nextPutAll: '(self at: '.
							(keyArray at: selectionIndex - self numberOfFixedFields)
								storeOn: strm.
							strm nextPutAll: ')'].
			Clipboard clipboardText: sel asText 			"no undo allowed"]! !

!DictionaryInspector methodsFor: 'menu' stamp: 'ar 10/31/2004 17:25'!
fieldListMenu: aMenu

	^ aMenu labels:
'inspect
copy name
references
objects pointing to this value
senders of this key
refresh view
add key
rename key
remove
basic inspect'
	lines: #(6 9)
	selections: #(inspectSelection copyName selectionReferences objectReferencesToSelection sendersOfSelectedKey refreshView addEntry renameEntry removeSelection inspectBasic)
! !

!DictionaryInspector methodsFor: 'menu' stamp: 'sd 11/20/2005 21:27'!
removeSelection
	selectionIndex = 0 ifTrue: [^ self changed: #flash].
	object removeKey: (keyArray at: selectionIndex - self numberOfFixedFields).
	selectionIndex := 0.
	contents := ''.
	self calculateKeyArray.
	self changed: #inspectObject.
	self changed: #selectionIndex.
	self changed: #fieldList.
	self changed: #selection.! !

!DictionaryInspector methodsFor: 'menu' stamp: 'jmv 12/10/2009 23:11'!
renameEntry
	| newKey aKey value |

	value := object at: (keyArray at: selectionIndex - self numberOfFixedFields).
	newKey := FillInTheBlank default request: 
'Enter new key, then type RETURN.
(Expression will be evaluated for value.)
Examples:  #Fred    ''a string''   3+4'
		 initialAnswer: (keyArray at: selectionIndex - self numberOfFixedFields) printString.
	aKey := Compiler evaluate: newKey.
	object removeKey: (keyArray at: selectionIndex - self numberOfFixedFields).
	object at: aKey put: value.
	self calculateKeyArray.
	selectionIndex := self numberOfFixedFields + (keyArray indexOf: aKey).
	self changed: #selectionIndex.
	self changed: #inspectObject.
	self changed: #fieldList.
	self update! !

!DictionaryInspector methodsFor: 'menu' stamp: 'jmv 12/10/2009 23:12'!
selectionReferences
	"Create a browser on all references to the association of the current selection."
	self selectionIndex = 0
		ifTrue: [^ self changed: #flash].
	object class == MethodDictionary
		ifTrue: [^ self changed: #flash].
	Smalltalk
		browseAllCallsOn: (object
				associationAt: (keyArray at: selectionIndex - self numberOfFixedFields))! !

!DictionaryInspector methodsFor: 'menu' stamp: 'jmv 12/10/2009 23:13'!
sendersOfSelectedKey
	"Create a browser on all senders of the selected key"
	| aKey |
	self selectionIndex = 0
		ifTrue: [^ self changed: #flash].
	((aKey := keyArray at: selectionIndex  - self numberOfFixedFields) isSymbol)
		ifFalse: [^ self changed: #flash].
	Smalltalk browseAllCallsOn: aKey! !

!DictionaryInspector methodsFor: 'initialize-release' stamp: 'jmv 12/10/2009 23:06'!
initialize

	super initialize.
	self calculateKeyArray! !

!DictionaryInspector methodsFor: 'private' stamp: 'apb 8/20/2004 21:15'!
numberOfFixedFields
	^ 2 + object class instSize! !


!Inspector class methodsFor: 'instance creation' stamp: 'jmv 12/10/2009 23:03'!
inspect: anObject
	"Answer an instance of me to provide an inspector for anObject."
	
	"We call basicNew to avoid a premature initialization; the instance method 
	inspect: anObject will do a self initialize."

	^self basicNew inspect: anObject! !

!Inspector class methodsFor: 'instance creation' stamp: 'jmv 12/10/2009 23:19'!
openAsMorphOn: anObject withLabel: aLabel
	"(Inspector openAsMorphOn: SystemOrganization) openInMVC"
	| window inspector |
	inspector _ self inspect: anObject.
	window _ (SystemWindow labelled: aLabel) model: inspector.
	window addMorph: (
		PluggableListMorph new
			doubleClickSelector: #inspectSelection;
			model: inspector 
			listGetter: #fieldList
			indexGetter: #selectionIndex
			indexSetter: #toggleIndex:
			menuGetter: #fieldListMenu:
			keystrokeAction: #inspectorKey:from:)
		frame: (0@0 corner: self horizontalDividerProportion @ self verticalDividerProportion).
	window addMorph: (PluggableTextMorph
			model: inspector 
			editorClass: inspector editorClass 
			textGetter: #contents 
			textSetter: #accept:
			selectionGetter: #contentsSelection 
			menuGetter: #paneMenu:shifted:editorClass:)
		frame: (self horizontalDividerProportion @0 corner: 1@self verticalDividerProportion).
	window addMorph: ((PluggableTextMorph 
			model: inspector 
			editorClass: inspector editorClass
			textGetter: #trash 
			textSetter: #trash:
			selectionGetter: #contentsSelection 
			menuGetter: #paneMenu:shifted:editorClass:)
					askBeforeDiscardingEdits: false)
		frame: (0@self verticalDividerProportion corner: 1@1).
	window setUpdatablePanesFrom: #(fieldList).
	^ window! !


!Set methodsFor: '*Tools-Inspector' stamp: 'jmv 12/10/2009 23:27'!
inspectorClass 
	^ SetInspector! !


!SetInspector methodsFor: 'accessing' stamp: 'PHK 6/29/2004 14:50'!
fieldList
	object
		ifNil: [^ Set new].
	^ self baseFieldList
		, (object array
				withIndexCollect: [:each :i | each ifNotNil: [i printString]])
		  select: [:each | each notNil]! !

!SetInspector methodsFor: 'menu' stamp: 'PHK 6/30/2004 12:16'!
fieldListMenu: aMenu

	^ aMenu labels:
'inspect
copy name
objects pointing to this value
refresh view
remove
basic inspect'
	lines: #( 5 8)
	selections: #(inspectSelection copyName objectReferencesToSelection update removeSelection inspectBasic)
! !

!SetInspector methodsFor: 'menu' stamp: 'sd 11/20/2005 21:27'!
removeSelection
	(selectionIndex <= object class instSize) ifTrue: [^ self changed: #flash].
	object remove: self selection.
	selectionIndex := 0.
	contents := ''.
	self changed: #inspectObject.
	self changed: #fieldList.
	self changed: #selection.
	self changed: #selectionIndex.! !

!SetInspector methodsFor: 'menu commands' stamp: 'sd 11/20/2005 21:27'!
copyName
	"Copy the name of the current variable, so the user can paste it into the 
	window below and work with is. If collection, do (xxx at: 1)."
	| sel |
	self selectionIndex <= (2 + object class instSize)
		ifTrue: [super copyName]
		ifFalse: [sel := '(self array at: '
						, (String streamContents: 
							[:strm | self arrayIndexForSelection storeOn: strm]) , ')'.
			Clipboard clipboardText: sel asText]! !

!SetInspector methodsFor: 'selecting' stamp: 'PHK 6/29/2004 15:33'!
arrayIndexForSelection
	^ (self fieldList at: selectionIndex) asInteger! !

!SetInspector methodsFor: 'selecting' stamp: 'PHK 6/29/2004 15:38'!
replaceSelectionValue: anObject
	^ object array at: self arrayIndexForSelection put: anObject! !

!SetInspector methodsFor: 'selecting' stamp: 'PHK 6/29/2004 15:35'!
selection
	selectionIndex = 0 ifTrue: [^ ''].
	selectionIndex = 1 ifTrue: [^ object].
	selectionIndex = 2 ifTrue: [^ object longPrintString].
	(selectionIndex - 2) <= object class instSize
		ifTrue: [^ object instVarAt: selectionIndex - 2].

	^ object array at: self arrayIndexForSelection! !


!WeakSet methodsFor: '*Tools-Inspector' stamp: 'jmv 12/10/2009 23:27'!
inspectorClass 
	^ WeakSetInspector! !


!WeakSetInspector methodsFor: 'accessing' stamp: 'nice 12/15/2007 11:59'!
fieldList
	| slotIndices |
	object ifNil: [^ Set new].
	
	"Implementation note: do not use objectArray withIndexCollect: as super
	because this might collect indices in a WeakArray, leading to constantly changing fieldList
	as explained at http://bugs.squeak.org/view.php?id=6812"
	
	slotIndices := (Array new: object size) writeStream.
	object array withIndexDo: [:each :i |
		(each notNil and: [each ~= flagObject]) ifTrue: [slotIndices nextPut: i printString]].
	
	^ self baseFieldList
		, slotIndices contents! !

!WeakSetInspector methodsFor: 'initialize-release' stamp: 'sd 11/20/2005 21:27'!
initialize
	super initialize.
	flagObject := object instVarNamed: 'flag'. ! !


!WeakSet reorganize!
('public' add: collect: do: do:after: includes: like: printElementsOn: remove:ifAbsent: size slowSize)
('private' fixCollisionsFrom: grow growTo: init: rehash scanFor:)
('*Tools-Inspector' inspectorClass)
!


!Set reorganize!
('accessing' atRandom: capacity like: size someElement)
('adding' add: add:withOccurrences:)
('converting' asSet)
('copying' copy)
('enumerating' collect: do: doWithIndex: union:)
('objects from disk' comeFullyUpOnReload:)
('private' array atNewIndex:put: findElementOrNil: fixCollisionsFrom: fullCheck grow growSize init: keyAt: noCheckAdd: rehash scanFor: swap:with: withArray:)
('removing' copyWithout: remove:ifAbsent:)
('testing' = includes: occurrencesOf:)
('explorer' hasContentsInExplorer)
('*Tools-Inspector' inspectorClass)
!

DictionaryInspector removeSelector: #dictionaryMenu:!
DictionaryInspector removeSelector: #inspect:!
!classDefinition: #Inspector category: #'Tools-Inspector'!
StringHolder subclass: #Inspector
	instanceVariableNames: 'object selectionIndex timeOfLastListUpdate selectionUpdateTime context'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Tools-Inspector'!
