'From Squeak5.3beta of 18 February 2020 [latest update: #19369] on 18 February 2020 at 3:55:50 pm'!
TestCase subclass: #AbstractInspectorTest
	instanceVariableNames: 'inspector target'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'ToolsTests-Inspector'!
AbstractInspectorTest subclass: #BasicInspectorTest
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'ToolsTests-Inspector'!
AbstractInspectorTest subclass: #ClassInspectorTest
	instanceVariableNames: ''
	classVariableNames: 'ClassVarA ClassVarB ClassVarC'
	poolDictionaries: 'PoolBar PoolFoo'
	category: 'ToolsTests-Inspector'!
AbstractInspectorTest subclass: #CompiledMethodInspectorTest
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'ToolsTests-Inspector'!
AbstractInspectorTest subclass: #ContextInspectorTest
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'ToolsTests-Inspector'!
ContextInspectorTest subclass: #ContextVariablesInspectorTest
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'ToolsTests-Debugger'!
AbstractInspectorTest subclass: #DictionaryInspectorTest
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'ToolsTests-Inspector'!
Object subclass: #InspecteeDummy
	instanceVariableNames: 'foo bar'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'ToolsTests-Inspector'!
StringHolder subclass: #Inspector
	instanceVariableNames: 'object selectionIndex timeOfLastListUpdate selectionUpdateTime context expression shouldStyleValuePane contentsTyped customFields styler fields '
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Tools-Inspector'!

!Inspector commentStamp: 'ct 1/12/2020 15:18' prior: 0!
I am a tool that allows to inspect and modify the internal representation of an object. As a StringHolder, the string I represent is the value of the currently selected variable of the observed object.!


!BasicInspector commentStamp: 'ct 1/12/2020 15:18' prior: 0!
I am a Inspector that displays the instance variables of my inspectee only, but not any kind of special information such as my sibling classes do.!

Inspector subclass: #ClassInspector
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Tools-Inspector'!

!ClassInspector commentStamp: 'ct 1/12/2020 15:25' prior: 0!
I am an Inspector that is specialized for inspecting Class objects.!

Inspector subclass: #CollectionInspector
	instanceVariableNames: 'numberOfFixedFields'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Tools-Inspector'!

!CollectionInspector commentStamp: 'ct 1/12/2020 15:26' prior: 0!
I am an Inspector that is specialized for inspecting collections. I provide extended access to the inspected collection's items, such as adding and removing items.!


!CompiledMethodInspector commentStamp: 'ct 1/12/2020 15:21' prior: 0!
I am an inspector specialized for inspecting CompiledMethods.!


!ContextInspector commentStamp: 'ct 1/12/2020 15:26' prior: 0!
I am an Inspector that is specialized for inspecting Contexts.!

Inspector subclass: #ContextVariablesInspector
	instanceVariableNames: 'fieldList '
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Tools-Debugger'!

!ContextVariablesInspector commentStamp: 'ct 1/13/2020 11:46' prior: 0!
I am an inspector that is specialized to inspecting the variables of a Context. I am typically displayed as port of a Debugger.!

CollectionInspector subclass: #DictionaryInspector
	instanceVariableNames: 'keyArray '
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Tools-Inspector'!

!DictionaryInspector commentStamp: 'ct 1/12/2020 15:26' prior: 0!
I am an Inspector that is specialized for inspecting Dictionarys.!

Model subclass: #InspectorBrowser
	instanceVariableNames: 'browser inspector '
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Tools-Inspector'!

!InspectorBrowser commentStamp: 'tcj 3/12/2018 07:55' prior: 0!
I am an inspector that also shows all messages the inspected objects can understand. I combine inspector and code browser.

InspectorBrowser openOn: Smalltalk!

Object subclass: #InspectorField
	instanceVariableNames: 'key title isTitleStylable valueGetter valueSetter expression isSpecial valueIsString type speciality'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Tools-Inspector'!

!InspectorField commentStamp: 'ct 1/13/2020 11:48' prior: 0!
I represent a single field of an Inspector in which I am composed. My client can completely configure my appearance and behavior.!

AbstractInspectorTest subclass: #InspectorTest
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'ToolsTests-Inspector'!
CollectionInspector subclass: #OrderedCollectionInspector
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Tools-Inspector'!

!OrderedCollectionInspector commentStamp: 'ct 1/12/2020 15:26' prior: 0!
I am an Inspector that is specialized for inspecting OrderedCollections.!

AbstractInspectorTest subclass: #OrderedCollectionInspectorTest
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'ToolsTests-Inspector'!
CollectionInspector subclass: #SetInspector
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Tools-Inspector'!

!SetInspector commentStamp: 'ct 1/12/2020 15:21' prior: 0!
I am an inspector that is specialized for inspecting Sets. I display 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.!

AbstractInspectorTest subclass: #SetInspectorTest
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'ToolsTests-Inspector'!
SetInspector subclass: #WeakSetInspector
	instanceVariableNames: 'flagObject '
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Tools-Inspector'!
SetInspectorTest subclass: #WeakSetInspectorTest
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'ToolsTests-Inspector'!

!FutureMaker methodsFor: '*Tools-Inspector' stamp: 'das 9/7/2005 10:09'!
defaultLabelForInspector
	"Answer the default label to be used for an Inspector window on the receiver."
	^self class name! !

!FutureMaker methodsFor: '*Tools-Inspector' stamp: 'das 9/7/2005 10:09'!
inspectorClass
	"Answer the class of the inspector to be used on the receiver.  Called by inspect; 
	use basicInspect to get a normal (less useful) type of inspector."

	^ Inspector! !


!Object methodsFor: '*Etoys-tiles' stamp: 'ct 1/4/2020 16:46'!
tearOffTile

	| tile |
	tile := TileMorph new referTo: self.
	self currentHand attachMorph: tile.
	^ tile! !

!Object methodsFor: '*Tools-Inspector' stamp: 'mt 4/5/2018 10:24'!
basicInspect
	"Create and schedule an Inspector in which the user can examine the 
	receiver's variables. This method should not be overriden."
	ToolSet basicInspect: self! !

!Object methodsFor: '*Tools-Inspector' stamp: 'mt 4/5/2018 10:24'!
inspect
	"Create and schedule an Inspector in which the user can examine the receiver's variables."
	ToolSet inspect: self! !

!Object methodsFor: '*Tools-Inspector' stamp: 'ct 2/15/2020 17:32'!
inspectFieldOrSelf

	^ (self respondsTo: #inspectField)
		ifTrue: [self inspectField]
		ifFalse: [self inspect]! !

!Object methodsFor: '*Tools-Inspector' stamp: 'mt 4/5/2018 10:24'!
inspectWithLabel: aLabel
	"Create and schedule an Inspector in which the user can examine the receiver's variables."
	ToolSet inspect: self label: aLabel! !

!Object methodsFor: '*Tools-Inspector' stamp: 'apb 7/14/2004 12:19'!
inspectorClass
	"Answer the class of the inspector to be used on the receiver.  Called by inspect; 
	use basicInspect to get a normal (less useful) type of inspector."

	^ Inspector! !


!AbstractInspectorTest methodsFor: 'assertions' stamp: 'ct 1/3/2020 23:55'!
assert: pattern matches: actual

	self
		assert: [(actual isString or: [actual isText]) and: [pattern match: actual]]
		description: [self comparingStringBetweenMatch: pattern and: actual]! !

!AbstractInspectorTest methodsFor: 'assertions' stamp: 'ct 1/6/2020 01:36'!
assertMenuWorks

	| aMenu labels |
	self
		shouldnt: [aMenu := inspector fieldListMenu: MenuMorph new]
		raise: Error, Warning, Halt.
	labels := aMenu items collect: #contents.
	self
		assert: [labels notEmpty];
		assert: [labels allSatisfy: #notEmpty].! !

!AbstractInspectorTest methodsFor: 'assertions' stamp: 'ct 2/14/2020 17:49'!
deny: pattern matches: actual

	self
		deny: [(actual isString or: [actual isText]) and: [pattern match: actual]]
		description: ['Actually matches {1}' format: {pattern}]! !

!AbstractInspectorTest methodsFor: 'assertions' stamp: 'ct 12/13/2019 14:43'!
shouldValuePaneContain: patterns

	self assert: patterns size equals: inspector fieldList size.
	patterns with: self valuePaneContents do: [:pattern :actual |
		self assert: pattern asString matches: actual].! !

!AbstractInspectorTest methodsFor: 'assertions' stamp: 'ct 1/5/2020 20:43'!
shouldntRaiseWhileDebugging: aBlock

	| context |
	context := aBlock asContext.
	(Process forContext: context priority: Processor activePriority - 1)
		runUntil: [:ctxt |
			self
				shouldnt: [inspector inspect: ctxt receiver]
				raise: Error, Warning, Halt.
			ctxt stepToSendOrReturn.
			(ctxt = context or: [ctxt hasSender: context]) not].! !

!AbstractInspectorTest methodsFor: 'assertions' stamp: 'ct 2/14/2020 17:32'!
shouldntValuePaneContain: pattern

	self valuePaneContents do: [:actual |
		self deny: pattern asString matches: actual].! !

!AbstractInspectorTest methodsFor: 'private' stamp: 'ct 1/12/2020 17:08'!
comparingStringBetweenMatch: pattern and: actual

	^ 'Pattern {1} is not matched by actual {2}' format: (
		{pattern. actual} collect: [:arg | arg printStringLimitedTo: 10])! !

!AbstractInspectorTest methodsFor: 'accessing' stamp: 'ct 1/11/2020 15:36'!
createTarget

	^ InspecteeDummy foo: 6 bar: Morph new! !

!AbstractInspectorTest methodsFor: 'accessing' stamp: 'ct 12/13/2019 14:21'!
valuePaneContents

	^ (1 to: inspector fieldList size) collect: [:index |
		inspector
			selectionIndex: index;
			contents].! !

!AbstractInspectorTest methodsFor: 'running' stamp: 'ct 1/5/2020 19:41'!
inspect: anObject

	^ Inspector inspect: target! !

!AbstractInspectorTest methodsFor: 'running' stamp: 'ct 1/5/2020 19:42'!
setTarget: anObject

	inspector ifNotNil: [
		inspector removeDependent: self].
	target := anObject.
	inspector := self inspect: anObject.
	inspector addDependent: self.! !

!AbstractInspectorTest methodsFor: 'running' stamp: 'ct 1/5/2020 19:43'!
setUp

	super setUp.
	self setTarget: self createTarget.! !

!AbstractInspectorTest methodsFor: 'tests' stamp: 'ct 2/16/2020 14:32'!
testCustomField

	[inspector addCustomField]
		valueSupplyingAnswer: #('*expression*' 'self identityHash').
	self assert: (inspector fieldList anySatisfy: [:title | '*identityHash' match: title]).
	self assert: target identityHash printString equals: inspector contents.! !

!AbstractInspectorTest methodsFor: 'tests' stamp: 'ct 1/11/2020 22:56'!
testDebugConstruction

	self shouldntRaiseWhileDebugging: [
		self createTarget]! !

!AbstractInspectorTest methodsFor: 'tests' stamp: 'ct 2/16/2020 14:08'!
testExpressions

	inspector fields with: self valuePaneContents do: [:field :content |
		| evaluatedExpression |
		evaluatedExpression := Compiler new
			evaluate: (inspector expressionForField: field)
			in: inspector doItContext
			to: inspector doItReceiver.
		[self assert: content equals: evaluatedExpression printString]
			on: TestFailure
			do: [self assert: content equals: evaluatedExpression asString]].! !

!AbstractInspectorTest methodsFor: 'tests' stamp: 'ct 1/5/2020 19:31'!
testMenus

	0 to: inspector fieldList size do: [:index |
		inspector selectionIndex: index.
		self assertMenuWorks].
	! !

!AbstractInspectorTest methodsFor: 'tests' stamp: 'ct 12/12/2019 09:01'!
testModifyValue

	inspector selectionIndex: 3 "foo".
	inspector accept: '2+3' notifying: nil.
	self assert: 5 asString equals: inspector contents.! !

!AbstractInspectorTest methodsFor: 'tests' stamp: 'ct 1/3/2020 23:35'!
testMorphic

	| toolBuilder widget |
	Smalltalk isMorphic ifFalse: [^ self "skip"].
	toolBuilder := MorphicToolBuilder new.
	[self
		shouldnt: [widget := toolBuilder open: inspector]
		raise: Error, Warning, Halt]
			ensure: [toolBuilder close: widget].! !

!AbstractInspectorTest methodsFor: 'tests' stamp: 'ct 1/3/2020 23:33'!
testMvc

	| toolBuilder widget |
	(Project current isKindOf: MVCProject) ifFalse: [^ self "skip"].
	toolBuilder := MVCToolBuilder new.
	[self
		shouldnt: [widget := toolBuilder open: inspector]
		raise: Error, Warning, Halt]
			ensure: ["toolBuilder close: widget"].! !

!AbstractInspectorTest methodsFor: 'tests' stamp: 'ct 12/13/2019 14:48'!
testPrintStringError

	^ self testPrintStringErrorSetting: [:dummy |
		target instVarAt: 1 put: dummy.
		inspector selectionIndex: 3 "instVarAt: 1"]! !

!AbstractInspectorTest methodsFor: 'tests' stamp: 'ct 1/12/2020 17:07'!
testPrintStringErrorSetting: aSetterBlock 

	aSetterBlock value: InspecteeDummy unprintableDummy.
	self
		assert: '*error*printString*'
		matches: inspector contents.! !

!AbstractInspectorTest methodsFor: 'tests' stamp: 'ct 2/14/2020 17:32'!
testValuePane

	self shouldntValuePaneContain: '*error*printString*'.! !

!AbstractInspectorTest methodsFor: 'updating' stamp: 'ct 1/11/2020 17:10'!
update: what

	"Mocking the widget"
	what = #fieldList
		ifTrue: [
			"Inspectors like to say 'self changed: #fieldList', so make them happy and ask for their new fancy field list."
			inspector fieldList]. 
	^ super update: what! !


!BasicInspectorTest methodsFor: 'accessing' stamp: 'ct 12/13/2019 14:59'!
createTarget

	^ Dictionary newFromPairs: #(foo bar)! !

!BasicInspectorTest methodsFor: 'running' stamp: 'ct 1/5/2020 19:43'!
inspect: anObject

	^ BasicInspector inspect: target "This should be equivalent to #on:"! !

!BasicInspectorTest methodsFor: 'tests' stamp: 'ct 12/13/2019 14:26'!
testFieldList

	self
		assert: #(self 'all inst vars' tally array)
		equals: (inspector fieldList collect: #asString).! !

!BasicInspectorTest methodsFor: 'tests' stamp: 'ct 12/13/2019 14:25'!
testValuePane

	self shouldValuePaneContain: {
		target asString.
		target longPrintString.
		target instVarNamed: #tally.
		target instVarNamed: #array }.! !


!Class methodsFor: '*Tools-Inspector' stamp: 'ct 1/4/2020 14:54'!
inspectorClass

	^ ClassInspector! !


!AbstractInspectorTest class methodsFor: 'testing' stamp: 'ct 12/12/2019 15:26'!
isAbstract

	^ self = AbstractInspectorTest! !

!AbstractInspectorTest class methodsFor: 'testing' stamp: 'ct 12/13/2019 17:24'!
shouldInheritSelectors

	^ true! !


!ClassInspectorTest methodsFor: 'accessing' stamp: 'ct 1/4/2020 15:34'!
createTarget

	ClassVarA := #classVarA.
	ClassVarB := #classVarB.
	ClassVarC := #classVarC.
	PoolFoo at: #fooKey put: #fooValue.
	PoolBar at: #barKey put: #barValue.
	^ self class! !

!ClassInspectorTest methodsFor: 'tests' stamp: 'ct 1/5/2020 23:02'!
testFieldList

	| fields |
	fields := inspector fieldList collect: #asString.
	self assert: #self equals: fields first.
	self assert: 'all inst vars' translated equals: fields second.
	self
		assert: #(self 'all inst vars') size + target class allInstVarNames size
			+ 3 "class vars" + 2 "pool vars"
		equals: fields size.
	self assert: #(ClassVarA ClassVarB ClassVarC) equals: ((fields last: 5) first: 3).
	self assert: #(PoolFoo PoolBar) equals: (fields last: 2).! !

!ClassInspectorTest methodsFor: 'tests' stamp: 'ct 1/13/2020 13:13'!
testModifyValue

	inspector selectFieldNamed: #ClassVarC.
	inspector accept: '2+3' notifying: nil.
	self assert: (2+3) asString equals: inspector contents.
	self assert: (2+3) equals: ClassVarC.! !

!ClassInspectorTest methodsFor: 'tests' stamp: 'ct 1/13/2020 13:13'!
testPrintStringError

	^ self testPrintStringErrorSetting: [:dummy |
		ClassVarC := dummy.
		inspector selectFieldNamed: #ClassVarC]! !

!ClassInspectorTest methodsFor: 'tests' stamp: 'ct 1/4/2020 15:35'!
testValuePane

	| valuePaneContents varContents |
	valuePaneContents := self valuePaneContents.
	varContents := valuePaneContents last: 5.
	self
		assert: ({ClassVarA. ClassVarB. ClassVarC} collect: #printString)
		equals: (varContents first: 3).
	self
		assert: ({PoolFoo. PoolBar} collect: #printString)
		equals: (varContents last: 2).! !


!CompiledMethodInspectorTest methodsFor: 'accessing' stamp: 'ct 1/12/2020 00:07'!
createTarget

	^ Compiler new
		compiledMethodFor: 'self withAll: #[67 97 114 112 101], #Squeak'
		in: nil
		to: String
		notifying: nil
		ifFail: [self error: 'Could not set up test target']! !

!CompiledMethodInspectorTest methodsFor: 'tests' stamp: 'ct 1/12/2020 00:32'!
testDebugConstruction

	^ self "pass: CompiledMethod really can't be created without the VM"! !

!CompiledMethodInspectorTest methodsFor: 'tests' stamp: 'ct 1/12/2020 00:23'!
testModifyArg

	| literalIndex |
	literalIndex := self valuePaneContents indexOf: #Squeak printString startingAt: 4.
	inspector selectionIndex: literalIndex.
	inspector accept: #Smalltalk printString notifying: nil.
	self assert: #Smalltalk printString equals: inspector contents.
	
	self assert: #CarpeSmalltalk equals: (target valueWithReceiver: String arguments: #()).! !

!CompiledMethodInspectorTest methodsFor: 'tests' stamp: 'ct 1/12/2020 00:23'!
testModifyValue

	| fields |
	fields := inspector fieldList collect: #asString.
	inspector selectionIndex: (fields indexOf: '61').
	inspector accept: '133' notifying: nil.
	self assert: '133' equals: inspector contents.
	
	self assert: 133 equals: (target at: 61).! !

!CompiledMethodInspectorTest methodsFor: 'tests' stamp: 'ct 1/13/2020 13:13'!
testPrintStringError

	^ self testPrintStringErrorSetting: [:dummy |
		target literalAt: 1 put: dummy.
		inspector selectFieldNamed: 'literal1']! !


!Compiler methodsFor: 'public access' stamp: 'ct 2/14/2020 16:42'!
compiledMethodFor: textOrStream in: aContext to: receiver environment: anEnvironment notifying: aRequestor ifFail: failBlock
	"Compiles the sourceStream into a parse tree, then generates code into a method, and answers it.  If receiver is not nil, then the text can refer to instance variables of that receiver (tools such as Inspector use this). If aContext is not nil, the text can refer to temporaries in that context (tools such as Debugger use this).  If anEnvironment is not nil, then all global bindings in the text are resolved in that environment instead of the current environment.  If aRequestor is not nil, then it will receive a notify:at: message before the attempt to evaluate is aborted."

	| methodNode method |
	methodNode := self
		compileNoPattern: textOrStream
		in: (self classForReceiver: receiver context: aContext)
		context: aContext
		environment: anEnvironment
		notifying: aRequestor
		ifFail: [^failBlock value].
	method := self interactive
		ifTrue: [ methodNode generateWithTempNames ] 
		ifFalse: [ methodNode generate ].
	^method! !

!Compiler methodsFor: 'public access' stamp: 'ct 2/16/2020 15:51'!
compiledMethodFor: textOrStream in: aContext to: receiver notifying: aRequestor ifFail: failBlock

	^ self compiledMethodFor: textOrStream in: aContext to: receiver environment: receiver class environment notifying: aRequestor ifFail: failBlock! !


!Context methodsFor: '*Tools-Inspector' stamp: 'ct 9/27/2019 16:59'!
inspectorClass

	^ ContextInspector! !


!ContextInspectorTest methodsFor: 'accessing' stamp: 'ct 1/12/2020 15:08'!
createTarget

	[[:arg1 :arg2 |
		| temp1 temp2 |
		temp1 := arg1 - 1.
		temp2 := arg2 - 1.
		temp1 / temp2]
	value: 3 value: 1]
		on: Error do: [:error |
			^ error signalerContext sender copy
				push: 42;
				yourself].
	self error: 'Failed to set up target context'! !

!ContextInspectorTest methodsFor: 'tests' stamp: 'ct 1/6/2020 00:48'!
testDebugConstruction

	self shouldntRaiseWhileDebugging: [
		[| foo | (foo := self) yourself] asContext]! !

!ContextInspectorTest methodsFor: 'tests' stamp: 'ct 1/12/2020 15:08'!
testFieldList

	self
		assert: #(self 'all inst vars' 'sender' 'pc' 'stackp' 'method' 'closureOrNil' 'receiver' '[arg1]' '[arg2]' '[temp1]' '[temp2]' '5')
		equals: (inspector fieldList collect: #asString).! !

!ContextInspectorTest methodsFor: 'tests' stamp: 'ct 12/13/2019 13:37'!
testModifyArg

	inspector selectionIndex: 4 "[arg2]".
	inspector accept: '2+3' notifying: nil.
	self assert: (2+3) asString equals: inspector contents.! !

!ContextInspectorTest methodsFor: 'tests' stamp: 'ct 12/13/2019 14:39'!
testModifyValue

	inspector selectionIndex: 5 "[temp1]".
	inspector accept: '2*3' notifying: nil.
	self assert: (2*3) asString equals: inspector contents.! !

!ContextInspectorTest methodsFor: 'tests' stamp: 'ct 1/13/2020 13:13'!
testPrintStringError

	^ self testPrintStringErrorSetting: [:dummy |
		inspector
			selectFieldNamed: '[temp1]';
			replaceSelectionValue: dummy]! !

!ContextInspectorTest methodsFor: 'tests' stamp: 'ct 1/12/2020 15:10'!
testValuePane

	self shouldValuePaneContain: {
		target asString.
		target longPrintString.
		'*createTarget'.
		'*'. '*'.
		'*a CompiledMethod*'. '*'.
		self printString.
		3. 1.
		2. 0.
		42 }.! !


!ContextVariablesInspectorTest methodsFor: 'running' stamp: 'ct 1/5/2020 19:43'!
inspect: anObject

	^ ContextVariablesInspector on: target! !

!ContextVariablesInspectorTest methodsFor: 'tests' stamp: 'ct 2/16/2020 14:33'!
testCustomField

	[inspector addCustomField]
		valueSupplyingAnswer: #('*expression*' 'self identityHash').
	self assert: (inspector fieldList anySatisfy: [:title | '*identityHash' match: title]).
	self assert: target receiver identityHash printString equals: inspector contents.
	
	[inspector addCustomField]
		valueSupplyingAnswer: #('*expression*' 'ThisContext identityHash').
	self assert: (inspector fieldList anySatisfy: [:title | '*identityHash' match: title]).
	self assert: target identityHash printString equals: inspector contents.! !

!ContextVariablesInspectorTest methodsFor: 'tests' stamp: 'ct 12/16/2019 19:15'!
testFieldList

	self
		assert: #(thisContext 'stack top' 'all temp vars' 'arg1' 'arg2' 'temp1' 'temp2')
		equals: (inspector fieldList collect: #asString).! !

!ContextVariablesInspectorTest methodsFor: 'tests' stamp: 'ct 12/16/2019 19:22'!
testPrintStringError

	^ self testPrintStringErrorSetting: [:dummy |
		target at: 3 put: dummy. "[temp1]"
		inspector selectionIndex: 6]! !

!ContextVariablesInspectorTest methodsFor: 'tests' stamp: 'ct 12/16/2019 19:18'!
testValuePane

	self shouldValuePaneContain: {
		target asString.
		42.
		(#('arg1:' 3 'arg2:' 1 'temp1:' 2 'temp2:' 0 '') joinSeparatedBy: #*).
		3. 1.
		2. 0 }.! !


!Debugger methodsFor: 'accessing' stamp: 'ct 1/3/2020 18:50'!
receiverInspectorObject: obj context: ctxt

	"set context before object so it can refer to context when building field list"
	receiverInspector context: ctxt.
	receiverInspector inspect: obj.
! !

!Debugger methodsFor: 'initialize' stamp: 'ct 1/3/2020 19:08'!
initializeFull
	"Expand the stack for the full debugger. Create inspectors."
	
	| oldIndex |
	oldIndex := contextStackIndex.
	contextStackIndex := 0.
	
	self expandStack.

	receiverInspector := Inspector on: nil.
	contextVariablesInspector := ContextVariablesInspector on: nil.
	
	self toggleContextStackIndex: oldIndex.! !

!Debugger methodsFor: 'private' stamp: 'ct 2/16/2020 17:30'!
contextStackIndex: anInteger oldContextWas: oldContext 
	"Change the context stack index to anInteger, perhaps in response to user selection."

	| isNewMethod |
	self saveReceiverInspectorState.
	self saveContextVariablesInspectorState.
	contextStackIndex := anInteger.
	anInteger = 0 ifTrue:
		[currentCompiledMethod := contents := nil.
		 self changed: #contextStackIndex.
		 self decorateButtons.
		 self contentsChanged.
		 contextVariablesInspector object: nil.
		 receiverInspector inspect: self receiver.
		 ^self].
	isNewMethod := oldContext isNil
		or: [oldContext method ~~ (currentCompiledMethod := self selectedContext method)].
	isNewMethod ifTrue:
		[contents := self selectedMessage.
		 self contentsChanged.
		 self pcRange].
	self changed: #contextStackIndex.
	self decorateButtons.
	contextVariablesInspector object: self selectedContext.
	self restoreContextVariablesInspectorState.
	receiverInspector inspect: self receiver.
	self restoreReceiverInspectorState.
	isNewMethod ifFalse:
		[self changed: #contentsSelection]! !

!Debugger methodsFor: 'user interface' stamp: 'ct 2/16/2020 14:44'!
restoreContextVariablesInspectorState
	"For the user's convenience. Save field selection and user-typed content in the context-variables inspector. See #saveContextVariablesInspectorState."

	contextVariablesInspectorState ifNotNil: [:stateForAll |
		self keyForContextVariablesInspectorState ifNotNil: [:keyForState |
			stateForAll 
				at: keyForState
				ifPresent: [:state |
					self contextVariablesInspector selectFieldNamed: state first.
					"state second ifNotNil: [:contentsTyped |
						self contextVariablesInspector
							setContentsTyped: contentsTyped]"]]].! !

!Debugger methodsFor: 'user interface' stamp: 'ct 2/16/2020 14:43'!
restoreReceiverInspectorState
	"For the user's convenience. Restore field selection and user-typed content in the receiver inspector. See #saveReceiverInspectorState."
	
	receiverInspectorState ifNotNil: [:stateForAll |
		self keyForReceiverInspectorState ifNotNil: [:keyForState |
			stateForAll 
				at: keyForState
				ifPresent: [:state |
					self receiverInspector selectFieldNamed: state first.
					"state second ifNotNil: [:contentsTyped |
						self receiverInspector
							setContentsTyped: contentsTyped]"]]].! !

!Debugger methodsFor: 'user interface' stamp: 'ct 1/13/2020 13:33'!
saveContextVariablesInspectorState
	"For the user's convenience. Save field selection and user-typed content in the context-variables inspector. See #restoreContextVariablesInspectorState."
	
	| stateToSave keyForState |
	self flag: #duplication.
	(keyForState := self keyForContextVariablesInspectorState)
		ifNil: [^ self].
	contextVariablesInspectorState
		ifNil: [contextVariablesInspectorState := IdentityDictionary new].
	stateToSave := {
		self contextVariablesInspector selectedFieldName.
		self contextVariablesInspector contentsTyped }.
	contextVariablesInspectorState
		at: keyForState
		put: stateToSave.! !

!Debugger methodsFor: 'user interface' stamp: 'ct 1/13/2020 13:33'!
saveReceiverInspectorState
	"For the user's convenience. Save field selection and user-typed content in the receiver inspector. See #restoreReceiverInspectorState."

	| stateToSave keyForState |
	self flag: #duplication.
	(keyForState := self keyForReceiverInspectorState)
		ifNil: [^ self].
	receiverInspectorState
		ifNil: [receiverInspectorState := IdentityDictionary new].
	stateToSave := {
		self receiverInspector selectedFieldName.
		self receiverInspector contentsTyped }.
	receiverInspectorState
		at: keyForState
		put: stateToSave.! !


!DictionaryInspectorTest methodsFor: 'accessing' stamp: 'ct 12/13/2019 14:40'!
createTarget

	^ Dictionary newFrom: {
		6 ->#six.
		7 -> #seven.
		11 -> #eleven }! !

!DictionaryInspectorTest methodsFor: 'tests' stamp: 'ct 1/13/2020 13:11'!
testAddEntry

	[inspector addEntry]
		valueSupplyingAnswer: #('*new key*' '3 ** 2').
	self
		assert: #(self '6' '7' '9' '11')
		equals: (inspector fieldList collect: #asString).
	self assert: inspector selectedFieldName equals: '9'.
	self assert: 'nil' equals: inspector contents.! !

!DictionaryInspectorTest methodsFor: 'tests' stamp: 'ct 1/5/2020 20:43'!
testDebugConstruction

	self shouldntRaiseWhileDebugging: [
		Dictionary new]! !

!DictionaryInspectorTest methodsFor: 'tests' stamp: 'ct 1/6/2020 00:36'!
testEllipsis

	| fieldList ellipsisIndex targetKeys values |
	self setTarget: ((1 to: 1000) collect: [:i | i -> i asWords] as: Dictionary).
	fieldList := inspector fieldList collect: #asString.
	
	self assert: #self matches: fieldList first.
	self assert: 1 + inspector maximumIndicesSize equals: fieldList size.
	ellipsisIndex := fieldList findFirst: [:field | '...' match: field] ifNone: [self fail: 'ellipsis not found'].
	self assert: inspector minimumLastIndicesSize equals: fieldList size - ellipsisIndex.
	targetKeys := target keysInOrder.
	self assert: [(targetKeys collect: #asString)
		beginsWith: (fieldList take: ellipsisIndex - 1) allButFirst].
	self assert: [(targetKeys collect: #asString)
		endsWith: (fieldList allButFirst: ellipsisIndex)].
	
	values := self valuePaneContents.
	self assert: '*not shown*' matches: (values at: ellipsisIndex).
	2 to: ellipsisIndex - 1 do: [:i |
		self assert: (target at: (targetKeys at: i - 1)) printString equals: (values at: i)].
	1 to: inspector minimumLastIndicesSize do: [:j |
		self assert: (target at: (targetKeys atLast: j)) printString equals: (values atLast: j)].! !

!DictionaryInspectorTest methodsFor: 'tests' stamp: 'ct 12/13/2019 14:44'!
testFieldList

	self
		assert: #(self '6' '7' '11')
		equals: (inspector fieldList collect: #asString).! !

!DictionaryInspectorTest methodsFor: 'tests' stamp: 'ct 12/13/2019 14:51'!
testPrintStringError

	^ self testPrintStringErrorSetting: [:dummy |
		target at: 7 put: dummy.
		inspector selectionIndex: 3 "7"]! !

!DictionaryInspectorTest methodsFor: 'tests' stamp: 'ct 1/13/2020 13:14'!
testRemoveSelection

	inspector selectFieldNamed: '7'.
	inspector removeSelection.
	self
		assert: #(self '6' '11')
		equals: (inspector fieldList collect: #asString).
	self deny: inspector selectedFieldName equals: '7'.
	self deny: 'seven' equals: inspector contents.! !

!DictionaryInspectorTest methodsFor: 'tests' stamp: 'ct 1/13/2020 13:14'!
testUpdate

	target at: 9 put: #newValue.
	self
		assert: #(self '6' '7' '11')
		equals: (inspector fieldList collect: #asString).
	inspector selectFieldNamed: '11'.
	inspector update.
	self assert: '11' equals: inspector selectedFieldName.
	self
		assert: #(self '6' '7' '9' '11')
		equals: (inspector fieldList collect: #asString).! !

!DictionaryInspectorTest methodsFor: 'tests' stamp: 'ct 12/13/2019 14:43'!
testValuePane

	self shouldValuePaneContain: {
		target asString.
		'#six'. '#seven'. '#eleven' }.! !


!FormInspectView class methodsFor: 'instance creation' stamp: 'ct 1/13/2020 13:15'!
openOn: aFormDictionary withLabel: aLabel
	"open a graphical dictionary in a window having the label aLabel. 
     aFormDictionary should be a dictionary containing as value a form."

     ^ aFormDictionary inspectWithLabel: aLabel
! !


!HtmlEntity methodsFor: 'user interface' stamp: 'ct 9/27/2019 21:44'!
inspectorClass

	^ HtmlEntityInspector! !


!InspecteeDummy methodsFor: 'accessing' stamp: 'ct 12/12/2019 08:39'!
bar

	^ bar! !

!InspecteeDummy methodsFor: 'accessing' stamp: 'ct 12/12/2019 09:06'!
bar: aValue

	bar := aValue! !

!InspecteeDummy methodsFor: 'accessing' stamp: 'ct 12/12/2019 08:39'!
foo

	^ foo! !

!InspecteeDummy methodsFor: 'accessing' stamp: 'ct 12/12/2019 09:05'!
foo: aValue

	foo := aValue! !

!InspecteeDummy methodsFor: 'accessing' stamp: 'ct 12/12/2019 09:06'!
foo: aValue bar: anotherValue

	self
		foo: aValue;
		bar: anotherValue.! !

!InspecteeDummy methodsFor: 'printing' stamp: 'ct 1/12/2020 17:05'!
printOn: aStream

	foo = self ifTrue: [
		self error: #somePrintError].
	^ super printOn: aStream! !


!InspecteeDummy class methodsFor: 'instance creation' stamp: 'ct 12/12/2019 08:39'!
foo: aValue bar: anotherValue

	^ self new
		foo: aValue bar: anotherValue;
		yourself! !

!InspecteeDummy class methodsFor: 'instance creation' stamp: 'ct 1/12/2020 17:07'!
unprintableDummy

	| dummy |
	dummy := self new.
	dummy foo: dummy.
	^ dummy! !


!Inspector methodsFor: 'accessing - selection' stamp: 'ct 1/11/2020 23:55'!
accept: aString notifying: aController

	| result |
	self selectionUnmodifiable ifTrue: [
		self inform: 'Selection is unmodifiable'.
		^ false].
	
	result := self object class evaluatorClass new
		evaluate: aString
		in: self doItContext
		to: self doItReceiver
		notifying: aController
		ifFail: [^ false].
	^ (self replaceSelectionValue: result)
		ifTrue: [
			self changed: #clearUserEdits.
			self disableValuePaneStyling];
		yourself! !

!Inspector methodsFor: 'accessing - selection' stamp: 'ct 1/4/2020 15:26'!
classOfSelection
	"Answer the class of the receiver's current selection"

	^ self selectionOrObject class! !

!Inspector methodsFor: 'accessing - selection' stamp: 'ct 12/16/2019 19:41'!
contentsIsString

	^ self selectedField
		ifNil: [true]
		ifNotNil: #valueIsString! !

!Inspector methodsFor: 'accessing - selection' stamp: 'ct 1/3/2020 18:12'!
hasSelection

	^ self selectedField notNil! !

!Inspector methodsFor: 'accessing - selection' stamp: 'ct 2/15/2020 20:33'!
replaceSelectionValue: anObject 
	"Set the value of the selected inspectee's variable to anObject."
	self selectedField type = #self
		ifTrue: [
			(self confirm: 'This will exchange the inspectee.' translated)
				ifFalse: [^ false].
			self object: anObject.
			self changed: #object.
			^ true].
	self selectionUnmodifiable ifTrue: [
		self error: 'Cannot replace selection'].
	self selectedField
		setValueFor: self
		to: anObject.
	self updateContents.
	^ true! !

!Inspector methodsFor: 'accessing - selection' stamp: 'ct 1/5/2020 22:19'!
selectedClass

	^ self object class! !

!Inspector methodsFor: 'accessing - selection' stamp: 'ct 1/3/2020 21:56'!
selectedField

	^ self fields
		at: self selectionIndex
		ifAbsent: [nil]! !

!Inspector methodsFor: 'accessing - selection' stamp: 'ct 12/16/2019 20:18'!
selectedInstVarName

	^ self selectedField instVarName! !

!Inspector methodsFor: 'accessing - selection' stamp: 'ct 2/15/2020 20:31'!
selection
	"Answer the value of the selected variable slot, that is an object."

	^ self selectedField getValueFor: self! !

!Inspector methodsFor: 'accessing - selection' stamp: 'ct 1/18/2020 19:02'!
selectionIsSpecial
	"Returns whether the selected slot does not represent a real object, such as allInstVars"

	^ self selectedField ifNotNil: #isSpecial ifNil: [false]! !

!Inspector methodsFor: 'accessing - selection' stamp: 'ct 1/18/2020 19:02'!
selectionIsVerySpecial
	"Returns whether the selected slot does not represent a part of the inspectee, such as an error message"

	^ self selectedField ifNotNil: #isVerySpecial ifNil: [false]! !

!Inspector methodsFor: 'accessing - selection' stamp: 'ct 1/11/2020 16:01'!
selectionOrObject
	"My selection. If nothing useful is selected, return my inspectee instead."

	^ (self hasSelection ==> [self selectionIsVerySpecial])
		ifFalse: [self selection]
		ifTrue: [self object]! !

!Inspector methodsFor: 'accessing - selection' stamp: 'ct 1/4/2020 16:46'!
selectionOrObjectField

	^ self fields
		at: self selectionIndex
		ifAbsent: [self fields first]! !

!Inspector methodsFor: 'accessing - selection' stamp: 'ct 1/5/2020 22:21'!
selectionUnmodifiable
	"Answer if the current selected variable is not modifiable via acceptance in the code pane.  For example, a selection of 'all inst vars' is unmodifiable."

	^ self selectedField
		ifNil: [true]
		ifNotNil: [:field | field isModifiable not]! !

!Inspector methodsFor: 'accessing - selection' stamp: 'ct 1/4/2020 14:56'!
typeOfSelection

	^ self selectedField ifNotNil: #type! !

!Inspector methodsFor: 'accessing' stamp: 'ct 1/5/2020 22:03'!
context: ctxt
	"Set the context of inspection. Currently not in use."

	self flag: #deprecate.
	context := ctxt! !

!Inspector methodsFor: 'accessing' stamp: 'ct 1/5/2020 22:05'!
doItReceiver
	"Answer the object that should be informed of the result of evaluating a text selection."

	^ self object! !

!Inspector methodsFor: 'accessing' stamp: 'ct 1/3/2020 21:44'!
expression
	"The code string in the code pane. Recorded for Inspector/Explorer switching. See #exploreObject."

	^ expression ifNil: ['']! !

!Inspector methodsFor: 'accessing' stamp: 'ct 1/3/2020 21:45'!
expression: aStringOrText
	"The code string in the code pane. Recorded for Inspector/Explorer switching. See #exploreObject."

	expression := aStringOrText.! !

!Inspector methodsFor: 'accessing' stamp: 'ct 12/9/2019 19:26'!
fieldList

	^ self fields collect: [:field |
		field titleStyledWith: self styler]! !

!Inspector methodsFor: 'accessing' stamp: 'ct 1/19/2020 13:36'!
fields

	 ^ fields ifNil: [fields := self createFields
		do: [:field | field addDependent: self];
		yourself]! !

!Inspector methodsFor: 'accessing' stamp: 'ct 1/5/2020 22:08'!
i1
	"This is the max index shown before skipping to the last i2 elements of very long arrays"
	self deprecated.
	^ self maximumIndicesSize
		- #(ellipsis) size
		- self minimumLastIndicesSize! !

!Inspector methodsFor: 'accessing' stamp: 'ct 1/5/2020 22:07'!
i2
	"This is the number of elements to show at the end of very long arrays"
	self deprecated.
	^ self minimumLastIndicesSize! !

!Inspector methodsFor: 'accessing' stamp: 'ct 10/2/2019 20:07'!
maximumIndicesSize
	"The maximum number of field slots that can be displayed. If there are more, they will be abbreviated."

	^ 100! !

!Inspector methodsFor: 'accessing' stamp: 'ct 1/5/2020 22:07'!
minimumLastIndicesSize
	"The minimum number of last fields to display if the list is abbreviated due to exceed of #maximumIndicesSize"

	^ 10! !

!Inspector methodsFor: 'accessing' stamp: 'ct 1/18/2020 16:27'!
object: anObject
	"Set anObject to be the object being inspected by the receiver."

	anObject == object
		ifTrue: [^ self update].
	self restoreSelectionAfter: [
		object := anObject.
		self initializeObject].
	self update.
	self
		changed: #inspectObject;
		changed: #windowTitle.! !

!Inspector methodsFor: 'accessing' stamp: 'ct 1/3/2020 21:47'!
setExpression: aString
	"Set the code string in the code pane after switching between Inspector/Explorer. See #inspectObject."

	self expression: aString.
	self changed: #expression.! !

!Inspector methodsFor: 'initialize-release' stamp: 'ct 1/18/2020 19:13'!
initialize

	super initialize.
	customFields := OrderedCollection new.
	selectionIndex := 0.
	self enableValuePaneStyling.! !

!Inspector methodsFor: 'initialize-release' stamp: 'ct 1/19/2020 13:35'!
initializeObject

	self resetFields.
	styler := nil.! !

!Inspector methodsFor: 'initialize-release' stamp: 'ct 1/6/2020 01:13'!
inspect: anObject 
	"Reinitialize the receiver so that it is inspecting anObject. Become an instance of the appropriate inspectorClass.
	
	Normally the receiver will be of the correct class (as defined by anObject inspectorClass), because it will have just been created by sending 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."

	| inspectorClass |
	inspectorClass := anObject inspectorClass.
	self class ~= inspectorClass ifTrue: [
		self class format = inspectorClass format
			ifTrue: [self primitiveChangeClassTo: inspectorClass basicNew]
			ifFalse: [self becomeForward: (self as: inspectorClass)]].
	
	self object: anObject.! !

!Inspector methodsFor: 'initialize-release' stamp: 'ct 1/19/2020 13:36'!
resetFields

	fields ifNotNil: [
		fields do: [:field |
			field removeDependent: self]].
	fields := nil.! !

!Inspector methodsFor: 'menu' stamp: 'ct 1/9/2020 15:54'!
addClassItemsTo: aMenu

	(self addCollectionItemsTo: aMenu)
		ifTrue: [aMenu addLine].
	aMenu addTranslatedList: #(
		('browse full (b)'			browseClass)
		('browse hierarchy (h)'		classHierarchy)
		('browse protocol (p)'		browseFullProtocol)).
	self typeOfSelection = #self ifFalse: [^ false].
	aMenu addTranslatedList: #(
		-
		('references... (r)'			browseVariableReferences)
		('assignments... (a)'		browseVariableAssignments)
		('class refs (N)'				browseClassRefs)).
	^ true! !

!Inspector methodsFor: 'menu' stamp: 'ct 2/15/2020 17:32'!
addCollectionItemsTo: aMenu
	"If the current selection is an appropriate collection, add items to aMenu that cater to that kind of selection. Return true iff at least one item was added."

	(self object respondsTo: #inspectField)
		ifFalse: [^ false].
	aMenu
		add: 'inspect element...' translated
		target: self object
		action: #inspectField.
	^ true! !

!Inspector methodsFor: 'menu' stamp: 'ct 1/18/2020 18:58'!
addFieldItemsTo: aMenu
	"Add field-related items to aMenu. Return true iff the selection is appropriate for further field items."

	(({nil. #self} includes: self typeOfSelection) or: [self selectionIsVerySpecial])
		ifTrue: [^ false].
	aMenu addTranslatedList: #(
		('copy name (c)'	copyName)).
	^ true! !

!Inspector methodsFor: 'menu' stamp: 'ct 1/4/2020 16:32'!
addInstVarItemsTo: aMenu

	aMenu addTranslatedList: #(
		('references (r)'			browseVariableReferences)
		('assignments (a)'		browseVariableAssignments)).
	^ true! !

!Inspector methodsFor: 'menu' stamp: 'topa 3/16/2015 17:31'!
fieldListMenu: aMenu
	"Arm the supplied menu with items for the field-list of the receiver"
	^ self menu: aMenu for: #(fieldListMenu fieldListMenuShifted:)
! !

!Inspector methodsFor: 'menu' stamp: 'ct 1/18/2020 19:17'!
fieldListMenu: aMenu shifted: shifted
	"Arm the supplied menu with items for the field-list of the receiver"
	^ self
		menu: aMenu
		for: #(fieldListMenu fieldListMenuShifted:)
		shifted: shifted! !

!Inspector methodsFor: 'menu' stamp: 'ct 1/4/2020 16:38'!
inspectorKey: aChar from: view
	"Respond to a Command key issued while the cursor is over my field list"

	^ aChar
		caseOf: {
			[$i]		->	[self inspectSelection].
			[$I]		->	[self exploreSelection].
			[$b]	->	[self browseClass].
			[$h]	->	[self classHierarchy].
			[$p]	->	[self browseFullProtocol].
			[$r]		->	[self browseVariableReferences].
			[$a]	->	[self browseVariableAssignments].
			[$N]	->	[self browseClassRefs].
			[$c]	->	[self copyName].
			[$t]		->	[self tearOffTile].
			[$v]	->	[self viewerForValue] }
		otherwise:	[self arrowKey: aChar from: view]! !

!Inspector methodsFor: 'menu' stamp: 'ct 2/15/2020 20:33'!
mainFieldListMenu: aMenu
	"Arm the supplied menu with items for the field-list of the receiver"
	<fieldListMenu>
	| field |
	aMenu addStayUpItemSpecial.
	
	field := self selectedField ifNil: [self fields first].
	field addObjectItemsFor: self to: aMenu.
	(self typeOfSelection = #self or: [self selectionIsVerySpecial])
		ifTrue: [
			self addCollectionItemsTo: aMenu].
	aMenu addLine.
	self typeOfSelection = #instVar
		ifTrue: [
			self addInstVarItemsTo: aMenu].
	self addFieldItemsTo: aMenu.
	field valueIsString ifFalse: [
			aMenu addLine.
			self addClassItemsTo: aMenu].
	
	(Smalltalk isMorphic and: [self selectionIsSpecial not])
		ifTrue: [
			aMenu addLine.
			field addEtoysItemsFor: self to: aMenu].

	^ aMenu! !

!Inspector methodsFor: 'menu' stamp: 'ct 2/16/2020 14:51'!
metaFieldListMenu: aMenu
	<fieldListMenu"Shifted: true">
	self flag: #ct "we need keyboard support for shifted menus. Maybe add an item 'More...'?".

	aMenu addLine.
	aMenu addTranslatedList: #(
		('Add field...'	#addCustomField)).
	(self selectedField ifNil: [false] ifNotNil: [:field | field isCustomFIeld])
		ifTrue: [
			self selectedField addCustomItemsFor: self to: aMenu].
	^ aMenu! !

!Inspector methodsFor: 'menu commands' stamp: 'ct 1/4/2020 15:26'!
browseClass
	"Open a full browser on the class of the selected item"

	^ ToolSet browseClass: self classOfSelection! !

!Inspector methodsFor: 'menu commands' stamp: 'ct 1/3/2020 22:14'!
browseVariableAssignments

	^ self selectedInstVarName
		ifNotNil: [:instVar | self systemNavigation
			browseAllStoresInto: instVar 
			from: self object class]
		ifNil: [self systemNavigation browseVariableAssignments: self object class]! !

!Inspector methodsFor: 'menu commands' stamp: 'ct 1/3/2020 22:14'!
browseVariableReferences

	^ self selectedInstVarName
		ifNotNil: [:instVar | self systemNavigation
			browseAllAccessesTo: instVar 
			from: self object class]
		ifNil: [self systemNavigation browseVariableReferences: self object class]! !

!Inspector methodsFor: 'menu commands' stamp: 'ct 2/16/2020 14:40'!
chaseSelectionPointers

	| selected saved |
	self hasSelection ifFalse: [^ self changed: #flash].
	selected := self selectionOrObject.
	saved := self object.
	self object: nil.
	^ [(selected respondsTo: #chasePointers)
		flag: #ct "Do we indeed need to isolate Tools-Inspector and Tools-Debugger?";
		flag: #ct "ToolSet";
		ifTrue: [selected chasePointers]
		ifFalse: [selected inspectPointers]]
			ensure: [self object: saved]! !

!Inspector methodsFor: 'menu commands' stamp: 'ct 1/5/2020 22:16'!
classHierarchy
	"Open a class list browser on the receiver's hierarchy."

	^ self systemNavigation browseHierarchy: self classOfSelection! !

!Inspector methodsFor: 'menu commands' stamp: 'ct 2/16/2020 14:04'!
copyName
	"Copy the name of the selected slot into clipboard."

	| name |
	name := self expressionForField: self selectedField.
	"name := self selectedField expressionWithBrackets.
	(self selection isKindOf: Collection)
		ifTrue: [name := '({1} at: 1)' format: {name}]."
	"ct: Removed this edge case - http://forum.world.st/Inspector-quot-Copy-name-quot-td5108269.html"
	Clipboard clipboardText: name.! !

!Inspector methodsFor: 'menu commands' stamp: 'ct 9/14/2019 20:44'!
exploreSelection

	^ self selectionOrObject explore! !

!Inspector methodsFor: 'menu commands' stamp: 'ct 1/3/2020 22:22'!
exploreSelectionPointers

	^ self selectionOrObject explorePointers! !

!Inspector methodsFor: 'menu commands' stamp: 'ct 9/14/2019 20:44'!
inspectBasic
	"Bring up a non-special inspector"

	^ self selectionOrObject basicInspect! !

!Inspector methodsFor: 'menu commands' stamp: 'ct 12/10/2019 09:09'!
inspectSelection
	"Create and schedule an Inspector on the receiver's model's currently selected object."

	self hasSelection ifFalse: [^ self changed: #flash].
	^ self selectionOrObject inspect! !

!Inspector methodsFor: 'menu commands' stamp: 'ct 1/3/2020 22:30'!
objectReferencesToSelection
	"Open a list inspector on all the objects that point to the value of the selected object."

	^ self systemNavigation
		browseAllObjectReferencesTo: self selectionOrObject
		except: (Array with: self with: self object)
		ifNone: [:obj | self changed: #flash]! !

!Inspector methodsFor: 'selecting' stamp: 'ct 1/6/2020 01:04'!
noteSelectionIndex: anInteger for: aSymbol
	
	aSymbol == #fieldList ifTrue:
		[selectionIndex := anInteger].! !

!Inspector methodsFor: 'selecting' stamp: 'ct 1/18/2020 16:33'!
privateToggleIndex: anInteger

	selectionUpdateTime := 0.
	selectionIndex = anInteger
		ifTrue: [ "same index, turn off selection"
			selectionIndex := 0.
			contents := '']
		ifFalse: [ "different index, new selection"
			self disableValuePaneStyling.
			selectionIndex := anInteger.
			contents := self generateContentsString].
	self
		changed: #selection;
		changed: #selectionIndex.! !

!Inspector methodsFor: 'selecting' stamp: 'ct 1/18/2020 20:13'!
selectField: aField 

	self selectionIndex: (self fields indexOf: aField)! !

!Inspector methodsFor: 'selecting' stamp: 'ct 2/16/2020 15:34'!
selectFieldNamed: aFieldName
	"Select the field that is labeled aFieldName, or nothing, is there is no match."

	aFieldName = self selectedFieldName
		ifTrue: [^ self].
	self disableValuePaneStyling.
	self selectionIndex: (aFieldName
		ifNotNil: [:name | self fields findFirst: [:field | field name = name]]
		ifNil: [0])! !

!Inspector methodsFor: 'selecting' stamp: 'ct 1/13/2020 13:11'!
selectedFieldName

	self selectionIndex ifNil: [^ nil].
	self selectionIndex isZero ifTrue: [^ nil].
	^ self fields
		at: self selectionIndex
		ifPresent: #name
		ifAbsent: [nil]! !

!Inspector methodsFor: 'selecting' stamp: 'ct 9/19/2019 02:20'!
selectionIndex

	^ selectionIndex! !

!Inspector methodsFor: 'selecting' stamp: 'ct 1/18/2020 16:34'!
selectionIndex: anIndex

	(self selectionIndex = anIndex and: [anIndex between: 1 and: self fields size])
		ifTrue: [^ self].
	self privateToggleIndex: anIndex.
	self hasUnacceptedEdits
		ifFalse: [self contentsChanged]
		ifTrue: [self changed: #codeChangedElsewhere].! !

!Inspector methodsFor: 'selecting' stamp: 'ct 2/15/2020 21:06'!
selectionPrintString

	| text |
	selectionUpdateTime := [
		text := self selection printStringLimitedTo: 5000
	] timeToRun.
	^ text! !

!Inspector methodsFor: 'selecting' stamp: 'ct 1/18/2020 16:33'!
toggleIndex: anInteger
	"If anInteger is the index of the current selection, deselect it. Otherwise, select the variable whose index is anInteger."

	self privateToggleIndex: anInteger.
	self contentsChanged.! !

!Inspector methodsFor: 'stepping' stamp: 'ct 1/11/2020 23:20'!
modelWakeUpIn: aWindow

	self update.! !

!Inspector methodsFor: 'stepping' stamp: 'ct 1/11/2020 23:20'!
stepAt: millisecondClockValue in: aWindow

	(Preferences smartUpdating and: [(millisecondClockValue - self timeOfLastListUpdate)
		> 8000]) ifFalse: [ "Not more often than once every 8 seconds"
			^ self updateContents].
	self update.
	timeOfLastListUpdate := millisecondClockValue.! !

!Inspector methodsFor: 'stepping' stamp: 'sma 6/15/2000 16:48'!
stepTimeIn: aSystemWindow
	^ (selectionUpdateTime ifNil: [0]) * 10 max: 1000! !

!Inspector methodsFor: 'stepping' stamp: 'sw 10/20/1999 15:54'!
timeOfLastListUpdate
	^ timeOfLastListUpdate ifNil: [timeOfLastListUpdate := 0]! !

!Inspector methodsFor: 'stepping' stamp: 'di 1/13/1999 14:36'!
wantsSteps
	^ true! !

!Inspector methodsFor: 'private' stamp: 'ct 2/16/2020 14:04'!
expressionForField: anInspectorField

	^ anInspectorField expression! !

!Inspector methodsFor: 'private' stamp: 'ct 2/16/2020 14:07'!
expressionWithBracketsForField: anInspectorField

	| exp |
	exp := self expressionForField: anInspectorField.
	(exp allSatisfy: #isAlphaNumeric)
		ifFalse: [exp := '({1})' format: {exp}].
	^ exp! !

!Inspector methodsFor: 'private' stamp: 'ct 1/3/2020 21:21'!
generateContentsString

	self hasSelection ifFalse: [^ nil].
	^ [self contentsIsString
		ifTrue: [self selection]
		ifFalse: [self selectionPrintString]]
			ifError: [self printStringErrorText]! !

!Inspector methodsFor: 'private' stamp: 'ct 1/13/2020 13:14'!
restoreSelectionAfter: aBlock

	| fieldName |
	fieldName := self selectedFieldName.
	aBlock value.
	self selectFieldNamed: fieldName.! !

!Inspector methodsFor: 'private' stamp: 'ct 1/12/2020 15:50'!
streamError: aMessageString doing: aBlock on: aStream

	^ self
		streamError: ('{1}. {2} to debug the error.' translated asText
			addAttribute: TextColor red;
			format: {
				aMessageString.
				Text string: 'Click here' translated attributes: {
					PluggableTextAttribute evalBlock: aBlock }})
		on: aStream! !

!Inspector methodsFor: 'private' stamp: 'ct 2/14/2020 17:52'!
streamError: aMessageString on: aStream

	aStream nextPut: ((self newFieldForType: #error)
		specialTitle: (Text
			string: ('<{1}>' format: {'error' translated})
			attributes: { TextColor red });
		beVerySpecial;
		stringGetter: [:object | '<{1}>' translated asText
			addAttribute: TextColor red;
			format: { aMessageString }];
		yourself)! !

!Inspector methodsFor: 'private' stamp: 'ct 1/12/2020 15:46'!
streamErrorDoing: aBlock on: aStream

	^ self
		streamError: 'An error occurred while inspecting this object' translated
		doing: aBlock
		on: aStream! !

!Inspector methodsFor: 'private' stamp: 'ct 1/6/2020 00:42'!
streamOn: aStream from: aList collectFields: aBlock

	aList withIndexDo: [:item :index |
		aStream nextPut: (aBlock cull: item cull: index)].! !

!Inspector methodsFor: 'private' stamp: 'ct 1/5/2020 23:19'!
streamOn: aStream truncate: aList collectFields: aBlock

	^ self
		streamOn: aStream
		truncate: aList
		collectFields: aBlock
		ellipsisFromText: [:truncated | self textForTruncationOf: truncated]! !

!Inspector methodsFor: 'private' stamp: 'ct 1/11/2020 16:10'!
streamOn: aStream truncate: aList collectFields: fieldBlock ellipsisFrom: ellipsisBlock

	"Optimized for performance, should be equivalent to pseudo:
	aStream nextPutAll: ((self truncateList: aList ellipsisFrom: ellipsisBlock) collect: fieldBlock)"
	| indicedList indicingCollector |
	indicedList := aList withIndexCollect: [:item :index | index -> item].
	indicingCollector := [:association | fieldBlock cull: association value cull: association key].
	aList size <= self maximumIndicesSize
		ifTrue: [
			aStream nextPutAll: (indicedList collect: indicingCollector).
			^ self].
	indicedList readStream in: [:readStream |
		aStream
			nextPutAll: ((readStream next: self maximumIndicesSize - self minimumLastIndicesSize - 1)
				collect: indicingCollector);
			nextPut: (ellipsisBlock cull:
				((readStream upToPosition: readStream size - self minimumLastIndicesSize) collect: #value));
			nextPutAll: (readStream upToEnd
				in: [:lastItems | self assert: [lastItems size = self minimumLastIndicesSize]];
				collect: indicingCollector)].! !

!Inspector methodsFor: 'private' stamp: 'ct 2/14/2020 17:14'!
streamOn: aStream truncate: aList collectFields: fieldBlock ellipsisFromText: textBlock

	^ self
		streamOn: aStream
		truncate: aList
		collectFields: fieldBlock
		ellipsisFrom: [:truncated | (self newFieldForType: #'...')
			specialTitle: '...';
			beVerySpecial;
			stringGetter: [:object | textBlock cull: truncated];
			yourself]! !

!Inspector methodsFor: 'toolbuilder' stamp: 'ct 1/6/2020 00:31'!
basicTextForTruncationOf: truncatedItems

	^ 'Indices {1} to {2} not shown' translated
		format: (Array
			with: truncatedItems first asString
			with: truncatedItems last asString)! !

!Inspector methodsFor: 'toolbuilder' stamp: 'ct 1/18/2020 18:58'!
buildCodePaneWith: builder
	
	^ builder pluggableCodePaneSpec new
		model: self;
		getText: #expression; 
		editText: #expression:;
		help: #helpText;
		selection: #contentsSelection; 
		menu: #codePaneMenu:shifted:;
		askBeforeDiscardingEdits: true;
		flag: #(bug helpWanted) "ct: This should NOT ask if the user selects a different slot!!";
		yourself! !

!Inspector methodsFor: 'toolbuilder' stamp: 'ct 1/11/2020 16:17'!
buildExploreButtonWith: builder
	
	^ builder pluggableButtonSpec new
		model: self;
		label: 'explore' translated;
		action: #exploreObject;
		help: 'Switch to an explorer tool' translated;
		yourself! !

!Inspector methodsFor: 'toolbuilder' stamp: 'ct 2/14/2020 14:49'!
buildFieldListWith: builder

	^ builder pluggableListSpec new
		model: self;
		list: #fieldList;
		getIndex: #selectionIndex;
		setIndex: #toggleIndex:;
		menu: #fieldListMenu:shifted:;
		dragItem: #dragFromFieldList:;
		dropItem: #dropOnFieldList:at:shouldCopy:;
		dropAccept: #wantsDropOnFieldList:type:source:;
		keyPress: #inspectorKey:from:;
		yourself! !

!Inspector methodsFor: 'toolbuilder' stamp: 'ct 1/11/2020 16:18'!
buildValuePaneWith: builder

	^ builder pluggableCodePaneSpec new
		model: self;
		name: #valuePane;
		getText: #contents;
		setText: #accept:notifying:;
		editText: #typeValue:;
		help: 'Selection details' translated;
		selection: #contentsSelection;
		menu: #codePaneMenu:shifted:;
		yourself! !

!Inspector methodsFor: 'toolbuilder' stamp: 'ct 9/26/2019 13:49'!
buildWith: builder
	"Inspector openOn: SystemOrganization"
	
	| windowSpec buttonOffset |
	buttonOffset := (Preferences standardButtonFont widthOfString: 'explore') * 3/2.
	windowSpec := self buildWindowWith: builder specs: {
		(0@0 corner: 0.3@0.71)  -> [self buildFieldListWith: builder].
		(0.3@0.0corner: 1@0.71) -> [self buildValuePaneWith: builder].
		(LayoutFrame fractions: (0@0.71 corner: 1@1) offsets: (0@0 corner: buttonOffset negated@0)) -> [self buildCodePaneWith: builder].
		(LayoutFrame fractions: (1@0.71 corner: 1@1) offsets: (buttonOffset negated@0 corner: 0 @ 0)) -> [self buildExploreButtonWith: builder].
	}.
	^ builder build: windowSpec! !

!Inspector methodsFor: 'toolbuilder' stamp: 'ct 1/12/2020 17:02'!
exploreObject
	"Switch to an explorer tool."
	
	| window currentBounds |
	self flag: #ct "A task for UIManager?".
	currentBounds := ToolBuilder default class getBoundsForWindow: self containingWindow.

	"Close first because MVC fiddles around with processes."
	self changed: #close. 
		
	window := ToolSet explore: self object.
	
	"---- In MVC, the lines after this will not be executed ---"

	window model setExpression: self expression.
	ToolBuilder findDefault setBoundsForWindow: window to: currentBounds.! !

!Inspector methodsFor: 'toolbuilder' stamp: 'ct 1/3/2020 22:57'!
helpText

	^ 'evaluate expressions here' translated! !

!Inspector methodsFor: 'toolbuilder' stamp: 'mt 4/12/2015 16:06'!
initialExtent
	"Answer the desired extent for the receiver when it is first opened on the screen.  "

	^ 350 @ 250! !

!Inspector methodsFor: 'toolbuilder' stamp: 'ct 2/16/2020 14:05'!
printStringErrorText

	| command |
	command := self contentsIsString
		ifTrue: [self selectedField expressionForModel: self]
		ifFalse: ['{1} printString' format: {
			self expressionWithBracketsForField: self selectedField}].
	^ '<{1} evaluate "{2}" to debug>' translated asText
		addAttribute: TextColor red;
		flag: #ct; "should be registered in ui themes"
		format: {
			('<b>error in {1}</b>' translated asTextFromHtml format: {#printString:}).
			command asText
				addAttribute: (PluggableTextAttribute evalBlock: [
					Compiler new evaluate: command in: self doItContext to: self doItReceiver]);
				yourself }! !

!Inspector methodsFor: 'toolbuilder' stamp: 'ct 2/15/2020 17:32'!
textForTruncationOf: truncatedItems

	^ ('<{1}!! To inspect a certain element, {2}>' translated asText
		addAttribute: TextEmphasis italic;
		format: {
			self basicTextForTruncationOf: truncatedItems.
			Smalltalk isMorphic
				ifTrue: ['click here' translated asText
					addAttribute: (PluggableTextAttribute evalBlock: [self selectionOrObject inspectFieldOrSelf]);
					yourself]
				ifFalse: [
					self flag: #ct "PluggableTextAttribute fails in MVC currently".
					'open the field list menu and choose "inspect element"' translated] })! !

!Inspector methodsFor: '*Protocols-Tools' stamp: 'ct 1/5/2020 22:01'!
browseFullProtocol
	"Open up a protocol-category browser on the value of the receiver's current selection.  If in mvc, an old-style protocol browser is opened instead."

	self flag: #ct "ToolSet?".
	Smalltalk isMorphic ifFalse: [^ self spawnProtocol].
	^ InstanceBrowser new openOnObject: self selectionOrObject showingSelector: nil! !

!Inspector methodsFor: '*Protocols-Tools' stamp: 'ct 9/14/2019 20:44'!
spawnFullProtocol
	"Spawn a window showing full protocol for the receiver's selection"

	^ ProtocolBrowser openFullProtocolForClass: self selectionOrObject class! !

!Inspector methodsFor: '*Protocols-Tools' stamp: 'ct 9/14/2019 20:45'!
spawnProtocol
	"Spawn a protocol on browser on the receiver's selection"

	^ ProtocolBrowser openSubProtocolForClass: self selectionOrObject class! !

!Inspector methodsFor: '*Etoys-menu commands' stamp: 'ct 1/4/2020 16:38'!
tearOffTile
	"Tear off a tile that refers to the receiver's selection, and place it in the mophic hand"

	self currentHand attachMorph: (TileMorph new referTo: self selectionOrObject)! !

!Inspector methodsFor: 'drag-drop' stamp: 'ct 2/14/2020 14:53'!
dragFromFieldList: index

	self selectionIndex: index.
	^ Sensor shiftPressed ifTrue: [self flag: #experimental; selectedField] ifFalse: [self selection]! !

!Inspector methodsFor: 'drag-drop' stamp: 'ct 2/16/2020 14:41'!
dropOnFieldList: anObject at: index shouldCopy: aBoolean

	aBoolean ifTrue: [
		self flag: #ct. "Write a separate hook for dropping into list besides dropping onto field"
		self addCustomField: anObject].
	self selectionIndex: index.
	^ self replaceSelectionValue: anObject! !

!Inspector methodsFor: 'styling' stamp: 'ct 2/15/2020 21:33'!
aboutToStyle: aStyler requestor: anObject

	"Note: Initialize the styler correctly even if we don't want to style the current selection. See #fieldList."
	aStyler
		environment: self environment;
		classOrMetaClass: self doItReceiver class;
		parseAMethod: false.
	^ anObject knownName = #valuePane ==> [self shouldStyleValuePane]! !

!Inspector methodsFor: 'styling' stamp: 'ct 1/11/2020 23:15'!
disableValuePaneStyling

	shouldStyleValuePane := false.! !

!Inspector methodsFor: 'styling' stamp: 'ct 1/11/2020 23:15'!
enableValuePaneStyling

	shouldStyleValuePane := true.! !

!Inspector methodsFor: 'styling' stamp: 'ct 1/11/2020 16:31'!
shouldStyleValuePane

	^ shouldStyleValuePane ifNil: [false]! !

!Inspector methodsFor: 'styling' stamp: 'ct 1/3/2020 21:50'!
styler

	| newStyler stylerClass |
	styler ifNotNil: [^ styler].
	
	stylerClass := self userInterfaceTheme stylerClass
		ifNil: [Smalltalk at: #SHTextStylerST80 ifAbsent: [^ nil]].
	newStyler := stylerClass new.
	self aboutToStyle: newStyler requestor: self.
	^ styler := newStyler! !

!Inspector methodsFor: 'styling' stamp: 'ct 1/13/2020 13:28'!
typeValue: aTextOrString

	self shouldStyleValuePane ifTrue: [^ self].
	contentsTyped := aTextOrString.
	self enableValuePaneStyling.
	self changed: #style.! !

!Inspector methodsFor: 'morphic ui' stamp: 'ct 1/3/2020 21:35'!
applyUserInterfaceTheme

	super applyUserInterfaceTheme.
	styler := nil.
	self changed: #fieldList.! !

!Inspector methodsFor: 'morphic ui' stamp: 'ct 9/19/2019 02:12'!
representsSameBrowseeAs: anotherInspector

	^ self object == anotherInspector object! !

!Inspector methodsFor: 'updating' stamp: 'ct 1/11/2020 23:08'!
update

	self restoreSelectionAfter: [
		self updateEntries.
		self updateContents].! !

!Inspector methodsFor: 'updating' stamp: 'ct 1/19/2020 13:24'!
update: what

	what = #field
		ifTrue: [
			| field |
			field := self selectedField.
			self updateEntries.
			self selectField: field].
	^ super update: what! !

!Inspector methodsFor: 'updating' stamp: 'ct 1/11/2020 23:17'!
updateContents
	"Force update contents of selected object"
	
	| newContents |
	self hasSelection ifFalse: [^ self].
	newContents := self generateContentsString.
	newContents = contents
		ifTrue: [^ self].
	contents := newContents.
	self hasUnacceptedEdits
		ifFalse: [self disableValuePaneStyling; contentsChanged]
		ifTrue: [self changed: #codeChangedElsewhere].
	self
		changed: #selection; flag: #ct; "Is there any update method that cares for #selection updates? Found none."
		changed: #selectionIndex.! !

!Inspector methodsFor: 'updating' stamp: 'ct 1/19/2020 13:35'!
updateEntries

	self resetFields.
	self changed: #fieldList.! !

!Inspector methodsFor: 'fields' stamp: 'ct 1/18/2020 19:12'!
createFields

	^ Array streamContents: [:stream |
		[self streamFieldsOn: stream]
			on: Error do: [:error |
				self streamErrorDoing: [self streamFieldsOn: stream] on: stream].
		self streamCustomFieldsOn: stream]! !

!Inspector methodsFor: 'fields' stamp: 'ct 2/14/2020 12:20'!
fieldAllInstVars

	^ (self newFieldForType: #allInstVars)
		specialTitle: 'all inst vars' translated;
		stringGetter: [:object | object longPrintString];
		yourself! !

!Inspector methodsFor: 'fields' stamp: 'ct 2/14/2020 14:41'!
fieldSelf

	^ (self newFieldForType: #self)
		stylableTitle: 'self';
		valueGetter: [:object | object];
		valueSetter: [:object :value | self object: value];
		yourself! !

!Inspector methodsFor: 'fields' stamp: 'ct 2/14/2020 14:42'!
fieldsInstVarsOn: aStream

	^ self
		streamOn: aStream
		from: object class allInstVarNames
		collectFields: [:name |
			((self newFieldForType: #instVar key: name)
				stylableTitle: name;
				valueGetter: [:object | object instVarNamed: name];
				valueSetter: [:object :value | object instVarNamed: name put: value];
				expression: name;
				yourself)]! !

!Inspector methodsFor: 'fields' stamp: 'ct 2/16/2020 14:42'!
fieldsItemsOn: aStream

	self flag: #(rename "are we fine with the name "items"?").
	^ self
		streamOn: aStream
		truncate: (1 to: object basicSize)
		collectFields: [:index |
			(self newFieldForType: #item key: index)
				title: index;
				valueGetter: [:object | object basicAt: index];
				valueSetter: [:object :value | object basicAt: index put: value];
				yourself]! !

!Inspector methodsFor: 'fields' stamp: 'ct 1/5/2020 20:46'!
newFieldForType: aSymbol

	^ InspectorField type: aSymbol! !

!Inspector methodsFor: 'fields' stamp: 'ct 1/5/2020 20:46'!
newFieldForType: aSymbol key: anObject

	^ InspectorField type: aSymbol key: anObject! !

!Inspector methodsFor: 'fields' stamp: 'ct 1/5/2020 22:53'!
streamBaseFieldsOn: aStream

	aStream
		nextPut: self fieldSelf;
		nextPut: self fieldAllInstVars.! !

!Inspector methodsFor: 'fields' stamp: 'ct 1/18/2020 19:22'!
streamCustomFieldsOn: aStream

	aStream nextPutAll: customFields! !

!Inspector methodsFor: 'fields' stamp: 'ct 1/5/2020 23:24'!
streamFieldsOn: aStream

	self
		streamBaseFieldsOn: aStream;
		fieldsInstVarsOn: aStream;
		fieldsItemsOn: aStream.! !

!Inspector methodsFor: 'custom fields' stamp: 'ct 2/6/2020 17:13'!
addCustomField

	^ self addCustomField: (self requestCustomFieldOrCancel: [^ self])! !

!Inspector methodsFor: 'custom fields' stamp: 'ct 2/16/2020 14:31'!
addCustomField: aField

	customFields add: aField.
	self update.
	self selectField: aField.! !

!Inspector methodsFor: 'custom fields' stamp: 'ct 2/14/2020 16:43'!
removeSelectedField

	self selectedField isCustomFIeld
		ifFalse: [^ self changed: #flash].
	customFields remove: self selectedField.
	self update.! !

!Inspector methodsFor: 'custom fields' stamp: 'ct 1/18/2020 19:39'!
requestCode: aMessageString initialAnswer: anAnswerString orCancel: aBlock

	| input |
	input := Project uiManager
		request: aMessageString
		initialAnswer: anAnswerString.
	input isEmptyOrNil ifTrue: [^ aBlock value].
	^ input! !

!Inspector methodsFor: 'custom fields' stamp: 'ct 1/18/2020 19:39'!
requestCode: aMessageString orCancel: aBlock

	^ self
		requestCode: aMessageString
		initialAnswer: 'self yourself'
		orCancel: aBlock! !

!Inspector methodsFor: 'custom fields' stamp: 'ct 1/18/2020 19:31'!
requestCompiledCode: aMessageString initialAnswer: anAnswerString orCancel: aBlock

	| input |
	input := Project uiManager
		request: aMessageString
		initialAnswer: anAnswerString.
	input isEmptyOrNil ifTrue: [^ aBlock value].
	^ Compiler new
		compiledMethodFor: input
		in: self doItContext
		to: self object
		notifying: nil
		ifFail: [^ self]! !

!Inspector methodsFor: 'custom fields' stamp: 'ct 1/18/2020 19:26'!
requestCompiledCode: aMessageString orCancel: aBlock

	^ self
		requestCompiledCode: aMessageString
		initialAnswer: 'self yourself'
		orCancel: aBlock! !

!Inspector methodsFor: 'custom fields' stamp: 'ct 2/6/2020 17:14'!
requestCustomFieldOrCancel: aBlock

	^ InspectorField requestCustomFor: self orCancel: aBlock! !


!BasicInspector methodsFor: 'initialize-release' stamp: 'ct 1/6/2020 01:16'!
inspect: anObject 
	"We don't want to change the inspector class. Only set anObject as the inspectee."
	self object: anObject! !


!ClassInspector methodsFor: 'fields' stamp: 'ct 2/14/2020 14:40'!
fieldsClassVarsOn: aStream
	
	^ self
		streamOn: aStream
		from: object classVarNames
		collectFields: [:name | (self newFieldForType: #classVar key: name)
			stylableTitle: name;
			valueGetter: [:object | object classPool at: name];
			valueSetter: [:object :value | object classPool at: name put: value];
			expression: name;
			yourself]! !

!ClassInspector methodsFor: 'fields' stamp: 'ct 2/14/2020 14:40'!
fieldsPoolDictionariesOn: aStream

	^ self
		streamOn: aStream
		from: (object sharedPools collect: [:ea | self environment keyAtIdentityValue: ea])
		collectFields: [:name :index |
			(self newFieldForType: #poolDictionary key: name)
				stylableTitle: name;
				valueGetter: [:object | object sharedPools at: index];
				valueSetter: [:object :value | object sharedPools at: index put: value];
				expression: name;
				yourself]! !

!ClassInspector methodsFor: 'fields' stamp: 'ct 1/6/2020 00:44'!
streamFieldsOn: aStream

	super streamFieldsOn: aStream.
	self
		fieldsClassVarsOn: aStream;
		fieldsPoolDictionariesOn: aStream.! !


!CollectionInspector methodsFor: 'menu' stamp: 'ct 1/11/2020 15:24'!
addCollectionItemsTo: aMenu

	super addCollectionItemsTo: aMenu.
	aMenu addTranslatedList: #(
		('refresh view'		update)
		('add entry'				addEntry)).
	^ true! !

!CollectionInspector methodsFor: 'menu' stamp: 'ct 1/11/2020 16:02'!
addFieldItemsTo: aMenu

	(super addFieldItemsTo: aMenu)
		ifFalse: [^ false].
	self assertItemSelectedOr: [^ false].
	aMenu addTranslatedList: #(
		('remove (x)'	removeSelection)).
	^ true! !

!CollectionInspector methodsFor: 'menu' stamp: 'ct 1/11/2020 23:23'!
inspectorKey: aChar from: view

	^ aChar = $x
		ifTrue: [self removeSelection]
		ifFalse: [super inspectorKey: aChar from: view].! !

!CollectionInspector methodsFor: 'menu commands' stamp: 'ct 1/11/2020 14:57'!
addEntry

	| newKey |
	newKey := self
		requestObject: 'Enter expression for new object' translated
		orCancel: [^ self].
	self addEntry: newKey.! !

!CollectionInspector methodsFor: 'menu commands' stamp: 'ct 1/9/2020 16:03'!
addEntry: anObject

	object add: anObject.
	self update.
	self selectionIndex: self numberOfFixedFields + (object asArray indexOf: anObject).! !

!CollectionInspector methodsFor: 'menu commands' stamp: 'ct 1/11/2020 16:04'!
removeSelection
	
	self assertItemSelectedOr: [^ self changed: #flash].
	object remove: self selection.
	self selectionIndex: 0.
	self update.! !

!CollectionInspector methodsFor: 'private' stamp: 'ct 1/11/2020 16:04'!
assertItemSelectedOr: aBlock

	^ self typeOfSelection = #item
		or: [aBlock cull: self selectedField].! !

!CollectionInspector methodsFor: 'private' stamp: 'ct 1/11/2020 23:27'!
numberOfFixedFields
	^ numberOfFixedFields! !

!CollectionInspector methodsFor: 'ui requests' stamp: 'ct 1/18/2020 19:28'!
requestObject: aMessageString initialAnswer: anAnswerString orCancel: aBlock

	| input |
	input := Project uiManager
		request: aMessageString
		initialAnswer: anAnswerString.
	input isEmptyOrNil ifTrue: [^ aBlock value].
	^ Compiler evaluate: input for: self object! !

!CollectionInspector methodsFor: 'ui requests' stamp: 'ct 1/11/2020 14:57'!
requestObject: aMessageString orCancel: aBlock

	^ self
		requestObject: aMessageString
		initialAnswer: String empty
		orCancel: aBlock! !

!CollectionInspector methodsFor: 'fields' stamp: 'ct 1/11/2020 23:26'!
streamFieldsOn: aStream

	aStream nextPut: self fieldSelf.
	numberOfFixedFields := aStream size.
	self fieldsItemsOn: aStream.! !


!CompiledMethodInspector methodsFor: 'fields' stamp: 'ct 2/14/2020 17:50'!
fieldByteCodes

	^ (self newFieldForType: #byteCodes)
		specialTitle: 'all bytecodes' translated;
		stringGetter: [:object | object symbolic];
		yourself! !

!CompiledMethodInspector methodsFor: 'fields' stamp: 'ct 2/14/2020 17:50'!
fieldHeader

	^ (self newFieldForType: #header)
		specialTitle: 'header' translated;
		stringGetter: [:object | object headerDescription];
		yourself! !

!CompiledMethodInspector methodsFor: 'fields' stamp: 'ct 2/14/2020 14:40'!
fieldsItemsOn: aStream

	^ self streamOn: aStream truncate: (object initialPC to: object size) collectFields: [:pc |
		(self newFieldForType: #item key: pc)
			title: pc;
			valueGetter: [:object | object at: pc];
			valueSetter: [:object :value | object at: pc put: value];
			yourself]! !

!CompiledMethodInspector methodsFor: 'fields' stamp: 'ct 2/14/2020 14:40'!
fieldsLiteralsOn: aStream

	^ self streamOn: aStream truncate: (1 to: object numLiterals) collectFields: [:index |
		(self newFieldForType: #literal key: index)
			title: 'literal' , index;
			valueGetter: [:object | object literalAt: index];
			valueSetter: [:object :value | object literalAt: index put: value];
			yourself]! !

!CompiledMethodInspector methodsFor: 'fields' stamp: 'ct 1/5/2020 23:24'!
streamFieldsOn: aStream

	aStream
		nextPut: self fieldSelf;
		nextPut: self fieldByteCodes;
		nextPut: self fieldHeader.
	self
		fieldsLiteralsOn: aStream;
		fieldsItemsOn: aStream.! !


!ContextInspector methodsFor: 'fields' stamp: 'ct 2/14/2020 14:40'!
fieldsStackOn: aStream

	^ self
		streamOn: aStream
		from: (object numTemps + 1 to: (object stackPtr ifNil: [^ self streamErrorOn: aStream]))
		collectFields: [:index |
			(self newFieldForType: #stackItem key: index)
				title: index;
				valueGetter: [:object | object at: index];
				valueSetter: [:object :value | object at: index put: value];
				yourself]! !

!ContextInspector methodsFor: 'fields' stamp: 'ct 2/14/2020 14:40'!
fieldsTempVarsOn: aStream

	^ self
		streamOn: aStream
		from: ([object tempNames] ifError: [^ self streamErrorDoing: [object tempNames] on: aStream])
		collectFields: [:name :index |
			(self newFieldForType: #tempVar key: name)
				title: ('[{1}]' format: {name});
				valueGetter: [:object | object namedTempAt: index];
				valueSetter: [:object :value | object namedTempAt: index put: value];
				yourself]! !

!ContextInspector methodsFor: 'fields' stamp: 'ct 1/12/2020 15:50'!
streamFieldsOn: aStream

	self streamBaseFieldsOn: aStream.
	self object ifNil: [^ self streamError: 'Cannot inspect a nil context' translated on: aStream].
	self object method ifNil: [^ self streamError: 'Cannot inspect a context with nil method' translated on: aStream].
	self
		fieldsInstVarsOn: aStream;
		fieldsTempVarsOn: aStream;
		fieldsStackOn: aStream.! !


!ContextVariablesInspector methodsFor: 'fields' stamp: 'ct 2/15/2020 21:06'!
fieldAllTempVars

	^ (self newFieldForType: #allTempVars)
		specialTitle: 'all temp vars' translated;
		stringGetter: [:object | object tempsAndValues];
		yourself! !

!ContextVariablesInspector methodsFor: 'fields' stamp: 'ct 2/16/2020 13:59'!
fieldSelf

	^ super fieldSelf
		stylableTitle: 'thisContext';
		yourself! !

!ContextVariablesInspector methodsFor: 'fields' stamp: 'ct 2/15/2020 21:49'!
fieldStackTop

	^ (self newFieldForType: #stackTop)
		specialTitle: (Text string: 'stack top' translated attributes: {TextEmphasis italic});
		valueGetter: [:object | object actualStackSize > 0 ifTrue: [object top] ifFalse: ['']];
		expression: 'ThisContext top';
		yourself! !

!ContextVariablesInspector methodsFor: 'fields' stamp: 'ct 2/14/2020 14:41'!
fieldsTempVarsOn: aStream

	^ self
		streamOn: aStream
		from: object tempNames
		collectFields: [:name :index |
			(self newFieldForType: #tempVar key: name)
				stylableTitle: name;
				valueGetter: [:object | object namedTempAt: index];
				valueSetter: [:object :value | object namedTempAt: index put: value];
				expression: name;
				yourself]! !

!ContextVariablesInspector methodsFor: 'fields' stamp: 'ct 1/5/2020 23:25'!
streamFieldsOn: aStream

	self object ifNil: [^ self].
	aStream
		nextPut: self fieldSelf;
		nextPut: self fieldStackTop;
		nextPut: self fieldAllTempVars.
	self fieldsTempVarsOn: aStream.! !

!ContextVariablesInspector methodsFor: 'styling' stamp: 'ct 1/18/2020 18:52'!
aboutToStyle: aStyler requestor: anObject

	"Note: Initialize the styler correctly even if we don't want to style the current selection. See #fieldList."
	aStyler context: self doItContext.
	^ super aboutToStyle: aStyler requestor: anObject! !

!ContextVariablesInspector methodsFor: 'private' stamp: 'ct 2/16/2020 14:04'!
expressionForField: anInspectorField

	^ anInspectorField expressionWithReceiverName: #ThisContext! !


!DictionaryInspector methodsFor: 'fields' stamp: 'ct 2/15/2020 19:07'!
fieldsItemsOn: aStream

	^ self
		streamOn: aStream
		truncate: keyArray
		collectFields: [:key |
			(self newFieldForType: #item key: key)
				title: key;
				valueGetter: [:object | object at: key];
				valueSetter: [:object :value | object at: key put: value];
				"expression: ('self at: {1}' format: {key});"
				yourself]! !

!DictionaryInspector methodsFor: 'initialize-release' stamp: 'ct 1/3/2020 21:28'!
initializeObject

	super initializeObject.
	self calculateKeyArray.! !

!DictionaryInspector methodsFor: 'menu' stamp: 'ct 1/11/2020 23:27'!
addFieldItemsTo: aMenu

	(super addFieldItemsTo: aMenu)
		ifFalse: [^ false].
	self selectedKey isSymbol ifTrue: [
		aMenu addTranslatedList: #(
			('senders of this key'		sendersOfSelectedKey))].
	aMenu addTranslatedList: #(
			('inspect key'				inspectKey)
			('references'				selectionReferences)
			('rename key'				renameEntry)).
	^ true! !

!DictionaryInspector methodsFor: 'ui requests' stamp: 'ct 2/14/2020 16:32'!
requestKeyInitialAnswer: anAnswerString orCancel: aBlock

	^ self
		requestObject: ('Enter expression for new key.\(Examples: {1})' withCRs translated
			format: {'#Fred    ''a string''   3+4'})
		initialAnswer: anAnswerString
		orCancel: aBlock! !

!DictionaryInspector methodsFor: 'ui requests' stamp: 'ct 1/11/2020 14:56'!
requestKeyOrCancel: aBlock

	^ self
		requestKeyInitialAnswer: String empty
		orCancel: aBlock! !

!DictionaryInspector methodsFor: 'menu commands' stamp: 'ct 1/11/2020 14:57'!
addEntry

	| newKey |
	newKey := self requestKeyOrCancel: [^ self].
	self addEntry: newKey.! !

!DictionaryInspector methodsFor: 'menu commands' stamp: 'ct 1/11/2020 23:28'!
addEntry: aKey

	object at: aKey put: nil.
	self update.
	self selectKey: aKey.! !

!DictionaryInspector methodsFor: 'menu commands' stamp: 'ct 1/11/2020 16:04'!
inspectKey
	"Create and schedule an Inspector on the receiver's model's currently selected key."

	self assertItemSelectedOr: [^ self].
	self selectedKey inspect.! !

!DictionaryInspector methodsFor: 'menu commands' stamp: 'ct 1/4/2020 00:58'!
refreshView

	self deprecated.
	^ self update! !

!DictionaryInspector methodsFor: 'menu commands' stamp: 'ct 1/11/2020 23:28'!
removeSelection

	self assertItemSelectedOr: [^ self changed: #flash].
	object removeKey: self selectedKey.
	selectionIndex := 0.
	self update.! !

!DictionaryInspector methodsFor: 'menu commands' stamp: 'ct 1/11/2020 16:04'!
renameEntry

	| newKey |
	self assertItemSelectedOr: [^ self flash].
	newKey := self
		requestKeyInitialAnswer: self selectedKey storeString
		orCancel: [^ self].
	^ self renameEntry: newKey! !

!DictionaryInspector methodsFor: 'menu commands' stamp: 'ct 1/11/2020 23:28'!
renameEntry: aKey

	object
		at: aKey put: self selection;
		removeKey: self selectedKey.
	self update.
	self selectKey: aKey.! !

!DictionaryInspector methodsFor: 'menu commands' stamp: 'ct 1/11/2020 16:04'!
selectionReferences
	"Create a browser on all references to the association of the current selection."

	self assertItemSelectedOr: [^ self changed: #flash].
	self flag: #ct "When does this work?".
	(object isMemberOf: MethodDictionary)
		ifTrue: [^ self changed: #flash]. "ct: why?"
	self systemNavigation browseAllCallsOn: (object associationAt: self selectedKey)! !

!DictionaryInspector methodsFor: 'menu commands' stamp: 'ct 9/26/2019 12:46'!
sendersOfSelectedKey
	"Create a browser on all senders of the selected key"

	| aKey |
	((aKey := self selectedKey) isSymbol)
		ifFalse: [^ self changed: #flash].
	SystemNavigation default browseAllCallsOn: aKey! !

!DictionaryInspector methodsFor: 'menu commands' stamp: 'ct 1/11/2020 23:08'!
updateEntries

	self calculateKeyArray.
	super updateEntries.! !

!DictionaryInspector methodsFor: 'accessing - selection' stamp: 'ct 1/9/2020 16:02'!
selectKey: aKey

	self selectionIndex: self numberOfFixedFields + (keyArray indexOf: aKey).! !

!DictionaryInspector methodsFor: 'accessing - selection' stamp: 'ct 1/11/2020 16:04'!
selectedKey

	self assertItemSelectedOr: [^ nil].
	^ self selectedField key! !

!DictionaryInspector methodsFor: 'toolbuilder' stamp: 'ct 1/3/2020 22:45'!
basicTextForTruncationOf: truncatedItems

	^ 'Keys {1} to {2} not shown' translated
		format: (Array
			with: truncatedItems first asString
			with: truncatedItems last asString)! !


!ExternalStructureInspector methodsFor: 'fields' stamp: 'ct 1/4/2020 01:33'!
fieldSelf

	^ super fieldSelf
		title: 'self: ', object defaultLabelForInspector;
		yourself! !

!ExternalStructureInspector methodsFor: 'fields' stamp: 'ct 2/14/2020 14:41'!
fieldsRecordsOn: aStream

	^ self
		streamOn: aStream
		from: self recordFieldList
		collectFields: [:field |
			(self newFieldForType: #record key: field)
				title: field;
				valueGetter: [:object | object perform: field];
				valueSetter: [:object :value | (field, ':') asSymbol with: value];
				yourself]! !

!ExternalStructureInspector methodsFor: 'fields' stamp: 'ct 1/5/2020 23:28'!
streamFieldsOn: aStream

	self
		streamBaseFieldsOn: aStream;
		fieldsRecordsOn: aStream.! !


!HtmlEntityInspector methodsFor: 'toolbuilder' stamp: 'ls 7/24/1998 01:40'!
initialExtent
	"Answer the desired extent for the receiver when it is first opened on the screen.  "

	^ 300 @ 300! !

!HtmlEntityInspector methodsFor: 'fields' stamp: 'ct 2/14/2020 14:41'!
fieldHtml

	^ (self newFieldForType: #html)
		specialTitle: 'asHtml';
		valueGetter: [:object | object asHtml];
		yourself! !

!HtmlEntityInspector methodsFor: 'fields' stamp: 'ct 1/5/2020 22:54'!
streamFieldsOn: aStream

	super streamFieldsOn: aStream.
	aStream nextPut: self fieldHtml.! !


!Inspector class methodsFor: 'instance creation' stamp: 'ct 1/18/2020 18:57'!
inspect: anObject 
	"Answer a new (sub)instance of me to provide an inspector for anObject."

	^ self new inspect: anObject! !

!Inspector class methodsFor: 'instance creation' stamp: 'ct 1/18/2020 18:57'!
on: anObject 
	"Answer a new instance of me to provide an inspector for anObject."
	
	^ self new object: anObject! !

!Inspector class methodsFor: 'instance creation' stamp: 'ct 1/3/2020 18:53'!
openOn: anObject

	^ self
		openOn: anObject
		withLabel: anObject defaultLabelForInspector! !

!Inspector class methodsFor: 'instance creation' stamp: 'ct 1/3/2020 18:35'!
openOn: anObject withLabel: label

	^ ToolBuilder open: (self on: anObject) label: label! !

!Inspector class methodsFor: '*Etoys-Squeakland-instance creation' stamp: 'ct 9/19/2019 00:13'!
horizontalDividerProportion
	self deprecated.
	^ 0.4! !


!InspectorBrowser methodsFor: 'accessing' stamp: 'ct 1/12/2020 15:13'!
inspect: anObject
	"Reinitialize the inspector so that it is inspecting anObject."

	inspector inspect: anObject.
	self updateBrowser.! !

!InspectorBrowser methodsFor: 'accessing' stamp: 'ct 1/4/2020 01:49'!
object: anObject
	"Set anObject to be the object being inspected by the receiver."

	inspector object: anObject.
	self updateBrowser.! !

!InspectorBrowser methodsFor: 'initialize-release' stamp: 'ct 1/4/2020 01:47'!
initialize

	super initialize.
	inspector := Inspector new.
	inspector addDependent: self.
	browser := Browser new.! !

!InspectorBrowser methodsFor: 'initialize-release' stamp: 'ct 1/18/2020 19:06'!
release

	inspector removeDependent: self.
	^ super release! !

!InspectorBrowser methodsFor: 'stepping' stamp: 'ct 12/16/2019 20:44'!
stepAt: millisecondClockValue in: aWindow
	
	inspector stepAt: millisecondClockValue in: aWindow.
	browser stepAt: millisecondClockValue in: aWindow.! !

!InspectorBrowser methodsFor: 'toolbuilder' stamp: 'ct 12/16/2019 20:43'!
buildWith: builder

	| windowSpec |
	windowSpec := self buildWindowWith: builder specs: {
		(0@0 corner: 0.3@0.3) -> [inspector buildFieldListWith: builder].
		(0.3@0 corner: 1.0@0.3) -> [inspector buildValuePaneWith: builder].
		(0@0.3 corner: 0.3@1.0) -> [browser buildMessageListWith: builder].
		(0.3@0.3 corner: 1.0@1.0) -> [browser buildCodePaneWith: builder].
	}.
	^ builder build: windowSpec! !

!InspectorBrowser methodsFor: 'toolbuilder' stamp: 'ct 12/16/2019 20:43'!
initialExtent

	^ inspector initialExtent * (3 / 2)! !

!InspectorBrowser methodsFor: 'updating' stamp: 'ct 1/4/2020 01:49'!
update: anAspect

	anAspect = #object ifTrue: [
		self updateBrowser].
	super update: anAspect.! !

!InspectorBrowser methodsFor: 'updating' stamp: 'ct 1/4/2020 01:49'!
updateBrowser

	browser setClass: inspector object class! !


!InspectorBrowser class methodsFor: 'instance creation' stamp: 'ct 1/4/2020 01:41'!
inspect: anObject 

	^ self new inspect: anObject! !

!InspectorBrowser class methodsFor: 'instance creation' stamp: 'ct 1/11/2020 22:57'!
on: anObject 

	^ self new object: anObject! !

!InspectorBrowser class methodsFor: 'instance creation' stamp: 'ct 1/4/2020 01:42'!
openOn: anObject

	^ self
		openOn: anObject
		withLabel: anObject defaultLabelForInspector! !

!InspectorBrowser class methodsFor: 'instance creation' stamp: 'ct 1/4/2020 01:45'!
openOn: anObject withLabel: label

	^ ToolBuilder open: (self inspect: anObject) label: label! !


!InspectorField methodsFor: 'menu' stamp: 'ct 2/15/2020 20:33'!
addCustomItemsFor: anInspector to: aMenu

	aMenu
		add: 'edit title...' translated target: self selector: #editTitle;
		add: 'edit field getter...' translated target: self selector: #editGetterFor: argument: anInspector;
		add: 'edit field setter...' translated target: self selector: #editSetterFor: argument: anInspector;
		add: 'remove field' translated action: #removeSelectedField.! !

!InspectorField methodsFor: 'menu' stamp: 'ct 1/19/2020 13:34'!
addCustomItemsForInspector: anInspector to: aMenu

	aMenu
		add: 'edit title...' translated target: self selector: #editTitle;
		add: 'edit field getter...' translated target: self selector: #editGetterFor: argument: anInspector;
		add: 'edit field setter...' translated target: self selector: #editSetterFor: argument: anInspector;
		add: 'remove field' translated action: #removeSelectedField.! !

!InspectorField methodsFor: 'menu' stamp: 'ct 2/15/2020 20:32'!
addEtoysItemsFor: anInspector to: aMenu

	aMenu addTranslatedList: {
		{ 'tile for this value (t)'.		[(self getValueFor: anInspector) tearOffTile] }.
		{ 'viewer for this value (v)'. [(self getValueFor: anInspector) beViewed] }}.! !

!InspectorField methodsFor: 'menu' stamp: 'ct 2/15/2020 20:32'!
addObjectItemsFor: anInspector to: aMenu

	self type = #'...' ifTrue: [^ self].
	aMenu addTranslatedList: {
		{'inspect (i)'.		[(self getValueFor: anInspector) inspect]}.
		{'explore (I)'.		[(self getValueFor: anInspector) explore]}.
		{'basic inspect'.	[(self getValueFor: anInspector) basicInspect].
			'Inspect all instvars of the object, regardless of\any possible specialized Inspector for this type' withCRs}}.
	self isSpecial ifTrue: [^ self].
	aMenu addTranslatedList: {
		#-.
		{'objects pointing to this value'.	#objectReferencesToSelection}.
		{'chase pointers'.					#chaseSelectionPointers}.
		{'explore pointers'.					[(self getValueFor: anInspector) explorePointers]} }.! !

!InspectorField methodsFor: 'accessing' stamp: 'ct 1/11/2020 15:55'!
beSpecial
	"Specify that the receiver does not represent a real object."

	speciality := #special.! !

!InspectorField methodsFor: 'accessing' stamp: 'ct 1/12/2020 16:51'!
beVerySpecial
	"Specify that the receiver does not represent a part of the inspectee (but rather an error message or something similar)."

	speciality := #verySpecial.! !

!InspectorField methodsFor: 'accessing' stamp: 'ct 1/4/2020 14:58'!
instVarName

	self type = #instVar ifFalse: [^ nil].
	^ self key! !

!InspectorField methodsFor: 'accessing' stamp: 'ct 1/12/2020 16:55'!
key
	"Optional. Type specific."

	^ key! !

!InspectorField methodsFor: 'accessing' stamp: 'ct 1/12/2020 16:55'!
key: anObject
	"Optional. Type specific."

	key := anObject! !

!InspectorField methodsFor: 'accessing' stamp: 'ct 12/10/2019 09:17'!
name

	^ self title asString! !

!InspectorField methodsFor: 'accessing' stamp: 'ct 1/4/2020 14:55'!
type

	^ type! !

!InspectorField methodsFor: 'accessing' stamp: 'ct 1/4/2020 14:55'!
type: aSymbol

	type := aSymbol! !

!InspectorField methodsFor: 'custom' stamp: 'ct 2/14/2020 15:07'!
editGetterFor: aStringHolder

	^ self editGetterFor: aStringHolder orCancel: []! !

!InspectorField methodsFor: 'custom' stamp: 'ct 2/16/2020 14:03'!
editGetterFor: aStringHolder orCancel: aBlock

	| code |
	code := self
		requestCode: 'Please enter value expression for field:' translated
		initialAnswer: self expression
		orCancel: [^ aBlock  value].
	^ self setGetterFor: aStringHolder to: code ifFail: aBlock! !

!InspectorField methodsFor: 'custom' stamp: 'ct 2/14/2020 15:07'!
editSetterFor: aStringHolder

	^ self editSetterFor: aStringHolder orCancel: []! !

!InspectorField methodsFor: 'custom' stamp: 'ct 2/6/2020 17:11'!
editSetterFor: anInspector orCancel: aBlock

	| code |
	code := self
		requestCode: 'Please enter setter expression for field:' translated
		initialAnswer: (self valueSetter ifNil: '[:value | self ___: value]' ifNotNil: #sourceString)
		orCancel: [^ aBlock value].
	^ self setSetterFor: anInspector to: code ifFail: aBlock! !

!InspectorField methodsFor: 'custom' stamp: 'ct 1/19/2020 13:33'!
editTitle

	^ self editTitleOrCancel: []! !

!InspectorField methodsFor: 'custom' stamp: 'ct 1/19/2020 13:33'!
editTitleOrCancel: aBlock

	| newTitle |
	newTitle := Project uiManager
		request: 'Please enter title for field:' translated
		initialAnswer: self title.
	newTitle isEmptyOrNil ifTrue: [^ aBlock value].
	self title: newTitle.
	self changed: #field.! !

!InspectorField methodsFor: 'custom' stamp: 'ct 1/18/2020 20:05'!
requestCode: aMessageString initialAnswer: anAnswerString orCancel: aBlock

	| input |
	input := Project uiManager
		request: aMessageString
		initialAnswer: anAnswerString.
	input isEmptyOrNil ifTrue: [^ aBlock value].
	^ input! !

!InspectorField methodsFor: 'custom' stamp: 'ct 1/18/2020 20:05'!
requestCode: aMessageString orCancel: aBlock

	^ self
		requestCode: aMessageString
		initialAnswer: 'self yourself'
		orCancel: aBlock! !

!InspectorField methodsFor: 'custom' stamp: 'ct 2/16/2020 14:28'!
requestCustomFor: aStringHolder orCancel: aBlock

	self setGetterFor: aStringHolder to: 'self yourself' ifFail: [^ self].
	self editGetterFor: aStringHolder orCancel: aBlock.! !

!InspectorField methodsFor: 'custom' stamp: 'ct 2/14/2020 18:07'!
setGetterFor: aStringHolder to: code ifFail: aBlock

	self valueGetter: (Compiler new
		compiledMethodFor: code
		in: aStringHolder doItContext
		to: aStringHolder doItReceiver
		environment: aStringHolder environment
		notifying: nil
		ifFail: [^ aBlock value]).
	self expression: code.
	self changed: #field.! !

!InspectorField methodsFor: 'custom' stamp: 'ct 2/15/2020 17:30'!
setSetterFor: aStringHolder to: code ifFail: aBlock

	| setter |
	setter := Compiler new
		evaluate: code
		in: aStringHolder doItContext
		to: aStringHolder doItReceiver
		environment: aStringHolder environment
		notifying: nil
		ifFail: [^ aBlock value]
		logged: false.
	self
		assert: (setter respondsTo: #value:)
		description: 'Setter must be evaluable like a block with one argument' translated.
	self valueSetter: [:object :value |
		setter value: value].
	self changed: #field.! !

!InspectorField methodsFor: 'accessing - value' stamp: 'ct 2/16/2020 14:00'!
expression
	"The code string to run for getting the receiver's value."

	^ self expressionWithReceiverName: #self! !

!InspectorField methodsFor: 'accessing - value' stamp: 'ct 1/4/2020 02:14'!
expression: aString
	"The code string to run for getting the receiver's value."

	expression := aString! !

!InspectorField methodsFor: 'accessing - value' stamp: 'ct 2/16/2020 14:00'!
expressionWithReceiverName: receiverName
	"The code string to run for getting the receiver's value."

	^ expression ifNil: [
		self valueGetter isCompiledCode
			ifTrue: [ "precompiled user code"
				self valueGetter getSource ]
			ifFalse: [ "evaluable"
				self
					generateExpressionFrom: self valueGetter
					argumentNames: {receiverName} ] ]! !

!InspectorField methodsFor: 'accessing - value' stamp: 'ct 12/16/2019 19:41'!
stringGetter: aSymbolOrBlock

	self
		valueGetter: aSymbolOrBlock;
		valueBeString.! !

!InspectorField methodsFor: 'accessing - value' stamp: 'ct 1/12/2020 16:55'!
valueBeString
	"Specify that the getter returns a string that is not to be quoted by the inspector."

	^ self valueIsString: true! !

!InspectorField methodsFor: 'accessing - value' stamp: 'ct 12/7/2019 20:37'!
valueGetter

	^ valueGetter! !

!InspectorField methodsFor: 'accessing - value' stamp: 'ct 1/12/2020 16:57'!
valueGetter: aSymbolOrBlock

	valueGetter := aSymbolOrBlock.! !

!InspectorField methodsFor: 'accessing - value' stamp: 'ct 1/12/2020 16:57'!
valueIsString
	"Indicates whether the getter returns a string that is not to be quoted by an inspector."

	^ valueIsString ifNil: [false]! !

!InspectorField methodsFor: 'accessing - value' stamp: 'ct 1/12/2020 16:57'!
valueIsString: aBoolean
	"Specify whether the getter returns a string that is not to be quoted by an inspector."

	valueIsString := aBoolean! !

!InspectorField methodsFor: 'accessing - value' stamp: 'ct 12/7/2019 21:11'!
valueSetter

	^ valueSetter! !

!InspectorField methodsFor: 'accessing - value' stamp: 'ct 12/7/2019 21:11'!
valueSetter: aBlockOrSymbol

	valueSetter := aBlockOrSymbol! !

!InspectorField methodsFor: 'private' stamp: 'ct 2/15/2020 20:11'!
generateExpressionFrom: aBlock argumentNames: argumentNames

	| blockNode arguments variables context receiver |
	blockNode := aBlock decompile.
	arguments := blockNode arguments collect: #name.
	variables := Dictionary new.
	receiver := aBlock receiver.
	receiver class allInstVarNames
		withIndexDo: [:name :index |
			variables at: name put: (receiver instVarAt: index)].
	context := aBlock outerContext.
	context tempNames
		withIndexDo: [:name :index |
			variables at: name put: (context namedTempAt: index)].
	blockNode nodesDo: [:node |
		{
			[node isVariableNode not].
			[| argumentIndex |
			argumentIndex := arguments indexOf: node name.
			argumentIndex isZero
				ifFalse: [node name: (argumentNames at: argumentIndex)];
				not].
			[variables at: node name
				ifPresent: [:value |
					value isLiteral
						ifTrue: [node becomeForward: (LiteralNode new key: value)];
						yourself]
				ifAbsent: [false]].
		} detect: #value ifNone: []].
	^ String streamContents: [:stream |
		blockNode
			printStatementsOn: stream
			indent: 0].! !

!InspectorField methodsFor: 'evaluating' stamp: 'ct 2/16/2020 14:25'!
getValueFor: anInspector

	self flag: #(rename discussion). "Is this a good name?"
	^ self valueGetter isCompiledCode
		ifTrue: [ "precompiled user code"
			self valueGetter
				valueWithReceiver: anInspector doItReceiver
				arguments: ({anInspector doItContext} first: self valueGetter numArgs)]
		ifFalse: [ "evaluable"
			self valueGetter value: anInspector object ]! !

!InspectorField methodsFor: 'evaluating' stamp: 'ct 2/15/2020 20:33'!
setValueFor: anInspector to: aValue

	self flag: #(rename discussion). "Is this a good name?"
	^ self valueSetter isCompiledCode
		ifTrue: [ "precompiled user code"
			| setterBlock |
			setterBlock := self valueSetter
				valueWithReceiver: anInspector doItReceiver
				arguments: (anInspector doItContext ifNotNil: [:ctxt | {ctxt}] ifNil: [#()]).
			setterBlock value: aValue ]
		ifFalse: [ "evaluable"
			self valueSetter value: anInspector object value: aValue ]! !

!InspectorField methodsFor: 'testing' stamp: 'ct 1/18/2020 19:46'!
isCustomFIeld

	^ self type = #custom! !

!InspectorField methodsFor: 'testing' stamp: 'ct 12/9/2019 18:56'!
isModifiable

	^ self valueSetter notNil! !

!InspectorField methodsFor: 'testing' stamp: 'ct 1/11/2020 15:55'!
isSpecial
	"True if the receiver does not represent a real object."

	^ speciality notNil! !

!InspectorField methodsFor: 'testing' stamp: 'ct 1/18/2020 20:51'!
isTitleStylable
	"For shout styling."

	^ isTitleStylable ifNil: [self title isNil]! !

!InspectorField methodsFor: 'testing' stamp: 'ct 1/11/2020 16:57'!
isVerySpecial
	"True if the receiver does not represent a real object."

	^ speciality = #verySpecial! !

!InspectorField methodsFor: 'accessing - title' stamp: 'ct 1/4/2020 02:15'!
makeTitleStylable
	"For shout styling."

	self makeTitleStylable: true! !

!InspectorField methodsFor: 'accessing - title' stamp: 'ct 1/4/2020 02:15'!
makeTitleStylable: aBoolean
	"For shout styling."

	isTitleStylable := aBoolean! !

!InspectorField methodsFor: 'accessing - title' stamp: 'ct 12/16/2019 19:24'!
specialTitle: aString

	self
		title: aString;
		beSpecial.! !

!InspectorField methodsFor: 'accessing - title' stamp: 'ct 12/9/2019 19:29'!
stylableTitle: aString

	self
		title: aString;
		makeTitleStylable.! !

!InspectorField methodsFor: 'accessing - title' stamp: 'ct 1/18/2020 19:34'!
title

	^ title ifNil: [self expression]! !

!InspectorField methodsFor: 'accessing - title' stamp: 'ct 12/16/2019 18:50'!
title: aStringOrText

	title := aStringOrText asStringOrText! !

!InspectorField methodsFor: 'accessing - title' stamp: 'ct 2/15/2020 20:34'!
titleStyledWith: aStyler

	| basicTitle |
	basicTitle := self title asStringOrText.
	self isSpecial
		ifTrue: [^ basicTitle asText
			addAllAttributes: {TextEmphasis italic};
			yourself].
	(self isTitleStylable and: [aStyler notNil])
		ifTrue: [
			| styledText |
			styledText := aStyler styledTextFor: basicTitle asText.
			((styledText runLengthFor: 1) = styledText size)
				flag: #workaround "PluggableListMorph only supports all-or-nothing formatting";
				ifTrue: [^ styledText]].
	^ basicTitle! !

!InspectorField methodsFor: 'printing' stamp: 'ct 1/12/2020 17:00'!
printOn: aStream

	super printOn: aStream.
	aStream
		nextPut: $<;
		print: self type;
		nextPut: $>.
	self name ifNotNil: [:name |
		aStream
			nextPutAll: ' named ';
			print: name].! !


!InspectorField class methodsFor: 'instance creation' stamp: 'ct 2/14/2020 15:06'!
requestCustomFor: aStringHolder

	^ self requestCustomFor: aStringHolder orCancel: []! !

!InspectorField class methodsFor: 'instance creation' stamp: 'ct 2/14/2020 15:06'!
requestCustomFor: aStringHolder orCancel: aBlock

	^ (self type: #custom)
		requestCustomFor: aStringHolder
		orCancel: [^ aBlock value]! !

!InspectorField class methodsFor: 'instance creation' stamp: 'ct 1/4/2020 14:57'!
type: aSymbol

	^ self new
		type: aSymbol;
		yourself! !

!InspectorField class methodsFor: 'instance creation' stamp: 'ct 1/4/2020 14:59'!
type: aSymbol key: anObject

	^ (self type: aSymbol)
		key: anObject
		yourself! !


!InspectorTest methodsFor: 'tests' stamp: 'ct 1/6/2020 01:24'!
testEllipsis

	| fieldList ellipsisIndex values |
	self setTarget: (1 to: 1000) asArray.
	fieldList := inspector fieldList collect: #asString.
	
	self assert: #(self 'all inst vars') equals: (fieldList first: 2).
	self assert: 2 + inspector maximumIndicesSize equals: fieldList size.
	ellipsisIndex := fieldList findFirst: [:field | '...' match: field] ifNone: [self fail: 'ellipsis not found'].
	self assert: inspector minimumLastIndicesSize equals: fieldList size - ellipsisIndex.
	self assert: [(target collect: #asString)
		beginsWith: ((fieldList take: ellipsisIndex - 1) allButFirst: 2)].
	self assert: [(target collect: #asString)
		endsWith: (fieldList allButFirst: ellipsisIndex)].
	
	values := self valuePaneContents.
	self assert: '*not shown*' matches: (values at: ellipsisIndex).
	3 to: ellipsisIndex - 1 do: [:i |
		self assert: (target at: i - 2) printString equals: (values at: i)].
	1 to: inspector minimumLastIndicesSize do: [:j |
		self assert: (target atLast: j) printString equals: (values atLast: j)].
	
	inspector selectionIndex: ellipsisIndex.
	self assertMenuWorks.! !

!InspectorTest methodsFor: 'tests' stamp: 'ct 12/12/2019 08:40'!
testFieldList

	self
		assert: #(self 'all inst vars' foo bar)
		equals: (inspector fieldList collect: #asString).! !

!InspectorTest methodsFor: 'tests' stamp: 'ct 12/13/2019 14:26'!
testValuePane

	self shouldValuePaneContain: {
		target asString.
		target longPrintString.
		target foo. target bar }.! !


!InstanceBrowser methodsFor: 'private' stamp: 'tfel 9/23/2016 13:13'!
setClassAndSelectorIn: csBlock
	| cm |
	super setClassAndSelectorIn: [:class :selector |
		(class notNil and: [selector notNil]) ifTrue: [^ csBlock value: class value: selector].
		cm := targetClass
					lookupSelector: (self selection asString findTokens: Character space) first asSymbol.
		cm ifNotNil: [^ csBlock value: (cm methodClass ifNil: [targetClass]) value: cm selector]].
	^ csBlock value: nil value: nil! !


!MethodFinder methodsFor: 'initialize' stamp: 'ct 2/15/2020 17:33'!
noteDangerous
	"Remember the methods with really bad side effects."

	Dangerous := Set new.
"Object accessing, testing, copying, dependent access, macpal, flagging"
	#(addInstanceVarNamed:withValue: haltIfNil copyAddedStateFrom: veryDeepCopy veryDeepCopyWith: veryDeepFixupWith: veryDeepInner: addDependent: evaluate:wheneverChangeIn: codeStrippedOut: playSoundNamed: isThisEverCalled isThisEverCalled: logEntry logExecution logExit)
		do: [:sel | Dangerous add: sel].

"Object error handling"
	#(cannotInterpret: caseError confirm: confirm:orCancel: doesNotUnderstand: error: halt halt: notify: notify:at: primitiveFailed shouldNotImplement subclassResponsibility)
		do: [:sel | Dangerous add: sel].

"Object user interface"
	#(basicInspect beep inform: inspect inspectWithLabel: notYetImplemented inspectElement inspectField)
		do: [:sel | Dangerous add: sel].

"Object system primitives"
	#(become: becomeForward: instVarAt:put: instVarNamed:put: nextInstance nextObject rootStubInImageSegment: someObject tryPrimitive:withArgs:)
		do: [:sel | Dangerous add: sel].

"Object private"
	#(errorImproperStore errorNonIntegerIndex errorNotIndexable errorSubscriptBounds: mustBeBoolean primitiveError: species storeAt:inTempFrame:)
		do: [:sel | Dangerous add: sel].

"Object, translation support"
	#(cCode: cCode:inSmalltalk: cCoerce:to: export: inline: returnTypeC: sharedCodeNamed:inCase: var:declareC:)
		do: [:sel | Dangerous add: sel].

"Object, objects from disk, finalization.  And UndefinedObject"
	#(comeFullyUpOnReload: objectForDataStream: readDataFrom:size: rehash saveOnFile storeDataOn: actAsExecutor executor finalize retryWithGC:until:   suspend)
		do: [:sel | Dangerous add: sel].

"No Restrictions:   Boolean, False, True, "

"Morph"
	#()
		do: [:sel | Dangerous add: sel].

"Behavior"
	#(obsolete confirmRemovalOf: copyOfMethodDictionary storeLiteral:on: addSubclass: removeSubclass: superclass: 
"creating method dictionary" addSelector:withMethod: compile: compile:notifying: compileAll compileAllFrom: compress decompile: defaultSelectorForMethod: methodDictionary: recompile:from: recompileChanges removeSelector: compressedSourceCodeAt: selectorAtMethod:setClass: allInstances allSubInstances inspectAllInstances inspectSubInstances thoroughWhichSelectorsReferTo:special:byte: "enumerating" allInstancesDo: allSubInstancesDo: allSubclassesDo: allSuperclassesDo: selectSubclasses: selectSuperclasses: subclassesDo: withAllSubclassesDo:
   "too slow->" crossReference removeUninstantiatedSubclassesSilently "too slow->" unreferencedInstanceVariables
"private" flushCache format:variable:words:pointers: format:variable:words:pointers:weak: format:variable:bitsUnitSize:pointers:weak: printSubclassesOn:level: basicRemoveSelector: addSelector:withMethod:notifying: addSelectorSilently:withMethod:)
		do: [:sel | Dangerous add: sel].

"CompiledMethod"
	#(defaultSelector)
		do: [:sel | Dangerous add: sel].

"Others "
	#("no tangible result" do: associationsDo:  
"private" adaptToCollection:andSend: adaptToNumber:andSend: adaptToPoint:andSend: adaptToString:andSend: instVarAt:put: asDigitsToPower:do: combinations:atATimeDo: doWithIndex: pairsDo: permutationsDo: reverseDo: reverseWith:do: with:do: withIndexDo: asDigitsAt:in:do: combinationsAt:in:after:do: errorOutOfBounds permutationsStartingAt:do: fromUser)
		do: [:sel | Dangerous add: sel].


	#(    fileOutPrototype addSpareFields makeFileOutFile )
		do: [:sel | Dangerous add: sel].
	#(recompile:from: recompileAllFrom: recompileChanges asPrototypeWithFields: asPrototype addInstanceVarNamed:withValue: addInstanceVariable addClassVarName: removeClassVarName: findOrAddClassVarName: instanceVariableNames: )
		do: [:sel | Dangerous add: sel].

 ! !


!MorphExtension methodsFor: 'other' stamp: 'ct 2/15/2020 17:33'!
inspectElement

	self deprecated: 'Use #inspectField'.
	^ self inspectField! !

!MorphExtension methodsFor: 'other' stamp: 'ct 2/15/2020 17:33'!
inspectField
	"Create and schedule an Inspector on the otherProperties and the 
	named properties."
	
	| key obj |
	key := UIManager default
		chooseFrom: self sortedPropertyNames
		values: self sortedPropertyNames
		title: 'Inspect which property?'.
	key ifNil: [^ self].
	obj := otherProperties
		at: key
		ifAbsent: [self perform: key].
	obj inspect.! !


!OrderedCollectionInspector methodsFor: 'fields' stamp: 'ct 2/14/2020 14:43'!
fieldsItemsOn: aStream

	^ self
		streamOn: aStream
		truncate: (1 to: self objectSize)
		collectFields: [:index |
			(self newFieldForType: #item key: index)
				title: index;
				valueGetter: [:object | object at: index];
				valueSetter: [:object :value | object at: index put: value];
				yourself]! !

!OrderedCollectionInspector methodsFor: 'private' stamp: 'ct 1/4/2020 00:52'!
objectSize
	"Single stepping through a debugger might observe the state of an OrderedCollection instance after creation by basicNew but before initialisation.  Thus 'object size' throws a DNU error for arithmetic on a nil value that needs to be handled here." 

	^ [ object size ] ifError: [ 0 ]
! !


!OrderedCollectionInspectorTest methodsFor: 'accessing' stamp: 'ct 12/13/2019 16:08'!
createTarget

	^ OrderedCollection withAll: #(foo bar clomp)! !

!OrderedCollectionInspectorTest methodsFor: 'tests' stamp: 'ct 1/13/2020 13:14'!
testAddEntry

	| entriesDiff newEntries oldEntries |
	oldEntries := inspector fieldList allButFirst collect: #asString.
	[inspector addEntry]
		valueSupplyingAnswer: #('*new object*' '6 * 7').
	newEntries := inspector fieldList allButFirst collect: #asString.
	entriesDiff := newEntries copyWithoutAll: oldEntries.
	self
		assert: (oldEntries copyWith: (oldEntries size + 1) asString)
		equals: newEntries.
	self assert: (oldEntries size + 1) asString equals: inspector selectedFieldName.
	self assert: '42' equals: inspector contents.! !

!OrderedCollectionInspectorTest methodsFor: 'tests' stamp: 'ct 1/6/2020 01:05'!
testDebugConstruction

	self shouldntRaiseWhileDebugging: [
		OrderedCollection new]! !

!OrderedCollectionInspectorTest methodsFor: 'tests' stamp: 'ct 1/6/2020 01:23'!
testEllipsis

	| fieldList ellipsisIndex values |
	self setTarget: (1 to: 1000) asOrderedCollection.
	fieldList := inspector fieldList collect: #asString.
	
	self assert: #self matches: fieldList first.
	self assert: 1 + inspector maximumIndicesSize equals: fieldList size.
	ellipsisIndex := fieldList findFirst: [:field | '...' match: field] ifNone: [self fail: 'ellipsis not found'].
	self assert: inspector minimumLastIndicesSize equals: fieldList size - ellipsisIndex.
	self assert: [(target collect: #asString)
		beginsWith: (fieldList take: ellipsisIndex - 1) allButFirst].
	self assert: [(target collect: #asString)
		endsWith: (fieldList allButFirst: ellipsisIndex)].
	
	values := self valuePaneContents.
	self assert: '*not shown*' matches: (values at: ellipsisIndex).
	2 to: ellipsisIndex - 1 do: [:i |
		self assert: (target at: i - 1) printString equals: (values at: i)].
	1 to: inspector minimumLastIndicesSize do: [:j |
		self assert: (target atLast: j) printString equals: (values atLast: j)].! !

!OrderedCollectionInspectorTest methodsFor: 'tests' stamp: 'ct 12/13/2019 16:27'!
testFieldList

	self
		assert: (((1 to: target size) collect: #asString) copyWithFirst: #self)
		equals: (inspector fieldList collect: #asString).! !

!OrderedCollectionInspectorTest methodsFor: 'tests' stamp: 'ct 12/13/2019 15:10'!
testPrintStringError

	^ self testPrintStringErrorSetting: [:dummy |
		target addFirst: dummy.
		inspector selectionIndex: 2 "1"]! !

!OrderedCollectionInspectorTest methodsFor: 'tests' stamp: 'ct 1/11/2020 17:00'!
testRemoveSelection

	| contents fields |
	inspector selectionIndex: 3.
	fields := inspector fieldList collect: #asString as: OrderedCollection.
	contents := inspector contents.
	inspector removeSelection.
	self
		assert: fields allButLast asArray "indices should be updated"
		equals: (inspector fieldList collect: #asString).
	self deny: contents equals: inspector contents.! !

!OrderedCollectionInspectorTest methodsFor: 'tests' stamp: 'ct 1/5/2020 19:44'!
testUninitialized
	"Single stepping through a debugger can observe the object state after creation but before initialisation."
	"Thus 'object size' may throw an axception for trying to do arithmetic on nil."
	"Modified OrderedCollectionInspector>>fieldList to call 'self objectSize' to handle this exception."
	
	self setTarget: OrderedCollection basicNew.
	self assert: #(self) equals: (inspector fieldList collect: #asString).
	self shouldValuePaneContain: #('*error*printString*').! !

!OrderedCollectionInspectorTest methodsFor: 'tests' stamp: 'ct 12/13/2019 16:27'!
testValuePane

	self shouldValuePaneContain:
		((target collect: #printString)
			copyWithFirst: target asString).! !


!SequenceableCollection methodsFor: 'enumerating' stamp: 'ct 2/17/2020 20:38'!
findFirst: aBlock ifNone: anotherBlock
	"Return the index of my first element for which aBlock evaluates as true. If no element is found, return the value of anotherBlock."

	| index |
	(index := self findFirst: aBlock) = 0
		ifTrue: [^ anotherBlock value].
	^ index! !

!SequenceableCollection methodsFor: '*Tools-Inspector' stamp: 'ct 2/15/2020 17:32'!
inspectField

	| choiceString selectionNames size |
	size := self size.
	size = 1 ifTrue: [^ self anyOne inspect].
	
	size <= 20 ifTrue: [
		| choice |
		selectionNames := self asArray withIndexCollect: [:item :index |
			'#{1}: {2}' format: {
				index.
				(item printStringLimitedTo: 25) copyWithout: Character cr }].
		choice := UIManager default chooseFrom: selectionNames title: 'Which element?'.
		choice = 0 ifTrue: [^ self].
		^ (self at: choice) inspect].
	
	choiceString := UIManager default request: 'Which element? (1 to: ', size printString, ')' initialAnswer: '1'.
	choiceString isEmptyOrNil ifTrue: [^ self].
	self
		at: choiceString asNumber
		ifPresent: [:item | ^ item inspect]
		ifAbsent: [Beeper beep].! !


!FloatArray methodsFor: '*Tools-Inspector' stamp: 'ct 1/18/2020 18:56'!
inspectorClass 
	"Answer the class of the inspector to be used on the receiver.  Called by inspect; 
	use basicInspect to get a normal (less useful) type of inspector."

	^OrderedCollectionInspector flag: #ct "why? Inspector is toally suitable for inspecting arrays."! !


!SetInspector methodsFor: 'fields' stamp: 'ct 2/14/2020 14:43'!
fieldsItemsOn: aStream

	| indices |
	indices := self itemIndices.
	^ self streamOn: aStream truncate: indices collectFields: [:index |
		(self newFieldForType: #item key: index)
			title: index;
			valueGetter: [:object | (object array at: index) enclosedSetElement];
			valueSetter: [:object :value | object array at: index put: value asSetElement];
			yourself]! !

!SetInspector methodsFor: 'private' stamp: 'ct 2/16/2020 14:55'!
arrayWithIndicesDo: elementAndIndexBlock

	object array withIndexDo: [:element :index |
		element ifNotNil: [
			elementAndIndexBlock
				value: element
				value: index]].! !

!SetInspector methodsFor: 'private' stamp: 'ct 2/16/2020 14:58'!
itemIndices

	^ Array new: (self object size ifNil: [^ #()]) streamContents: [:stream |
		self arrayWithIndicesDo: [:item :index |
			stream nextPut: index]]! !

!SetInspector methodsFor: 'toolbuilder' stamp: 'ct 9/27/2019 19:12'!
inspectorOverflowText

	^ ('<{1} more elements not shown!!>' format: {self object size - self maximumIndicesSize})
		asText
			addAttribute: TextEmphasis italic;
			yourself! !


!SetInspectorTest methodsFor: 'accessing' stamp: 'ct 12/13/2019 16:42'!
createTarget

	^ Set withAll: {#foo. #bar. #clomb. nil. #kiffle}! !

!SetInspectorTest methodsFor: 'tests' stamp: 'ct 1/11/2020 17:26'!
testAddEntry

	|  entriesDiff newContents oldContents |
	oldContents := self valuePaneContents allButFirst asSet.
	[inspector addEntry]
		valueSupplyingAnswer: #('*new object*' 'self class').
	self assert: target class asString equals: inspector contents.
	newContents := self valuePaneContents allButFirst asSet.
	entriesDiff := newContents copyWithoutAll: oldContents.
	self assert: 1 equals: entriesDiff size.
	self assert: target class asString equals: entriesDiff anyOne.! !

!SetInspectorTest methodsFor: 'tests' stamp: 'ct 1/6/2020 01:06'!
testDebugConstruction

	self shouldntRaiseWhileDebugging: [
		target class new]! !

!SetInspectorTest methodsFor: 'tests' stamp: 'ct 1/6/2020 00:31'!
testEllipsis

	| fieldList ellipsisIndex |
	self setTarget: ((1 to: 1000) collect: [:i | Object new] as: Set).
	fieldList := inspector fieldList collect: #asString.
	
	self assert: #self matches: fieldList first.
	self assert: 1 + inspector maximumIndicesSize equals: fieldList size.
	ellipsisIndex := fieldList findFirst: [:field | '...' match: field] ifNone: [self fail: 'ellipsis not found'].
	self assert: inspector minimumLastIndicesSize equals: fieldList size - ellipsisIndex.! !

!SetInspectorTest methodsFor: 'tests' stamp: 'ct 1/5/2020 19:44'!
testEnclosedSetElements

	| valuePaneContents |
	self setTarget: (target class newFrom: #(foo bar clomb)).
	
	valuePaneContents := self valuePaneContents.
	self deny: [valuePaneContents allButFirst includes: nil].! !

!SetInspectorTest methodsFor: 'tests' stamp: 'ct 12/13/2019 16:55'!
testFieldList

	| fields |
	fields := inspector fieldList collect: #asString.
	self assert: #self equals: fields first.
	self assert: target size equals: fields allButFirst asSet size.
	self assert: [(1 to: target array size) includesAllOf: (fields allButFirst asSet collect: #asNumber)].! !

!SetInspectorTest methodsFor: 'tests' stamp: 'ct 2/14/2020 17:59'!
testPrintStringError

	^ self testPrintStringErrorSetting: [:dummy |
		target
			removeAll;
			add: dummy.
		inspector
			update;
			selectionIndex: 2 "1"]! !

!SetInspectorTest methodsFor: 'tests' stamp: 'ct 1/11/2020 17:26'!
testRemoveSelection

	| entriesDiff newContents oldContents selectedContents |
	oldContents := self valuePaneContents allButFirst asSet.
	inspector selectionIndex: 3.
	selectedContents := inspector contents.
	inspector removeSelection.
	newContents := self valuePaneContents allButFirst asSet.
	entriesDiff := oldContents copyWithoutAll: newContents.
	self assert: 1 equals: entriesDiff size.
	self assert: selectedContents equals: entriesDiff anyOne.! !

!SetInspectorTest methodsFor: 'tests' stamp: 'ct 1/5/2020 19:44'!
testUninitialized
	"Single stepping through a debugger can observe the object state after creation but before initialisation."
	"Thus 'object size' may throw be nil."
	
	self setTarget: target class basicNew.
	self assert: #(self) equals: (inspector fieldList collect: #asString).
	self shouldValuePaneContain: #('*error*printString*').! !

!SetInspectorTest methodsFor: 'tests' stamp: 'ct 1/4/2020 01:23'!
testValuePane

	| valuePaneContents |
	self assert: 1 + target size equals: inspector fieldList size.
	valuePaneContents := self valuePaneContents.
	self assert: target printString matches: valuePaneContents first.
	self
		assert: (target collect: #printString as: Set)
		equals: (valuePaneContents allButFirst as: Set).! !


!SqueakMessageCategoriesHelp methodsFor: 'menu' stamp: 'ct 10/3/2019 02:15'!
menu
"This category includes all methods related to menus, often context menus in particular. It contains methods defining the menu as well as often callbacks for the labels of menu items or the actions to be executed. Sometimes the menus are split up in different categories if there are multiple menus or submenus."

	^ {ObjectExplorer>>#mainTreeListMenu: . SystemWindow>>#makeClosable}! !


!StandardToolSet class methodsFor: 'inspecting' stamp: 'ct 1/3/2020 21:33'!
basicInspect: anObject
	"Open a basic inspector on the given object."
	^ BasicInspector openOn: anObject! !


!WeakSet methodsFor: '*Tools-Inspector' stamp: 'ct 2/16/2020 14:58'!
inspectorClass

	^ WeakSetInspector! !


!WeakSetInspector methodsFor: 'private' stamp: 'ct 2/16/2020 14:59'!
arrayWithIndicesDo: elementAndIndexBlock

	"Implementation note: do not use array withIndexCollect: because this might collect indices in a WeakArray, leading to constantly changing fieldList as explained at http://bugs.squeak.org/view.php?id=6812"
	| flag |
	self flag: #ct. "extension method?"
	flag := object instVarNamed: #flag.
	object array withIndexDo: [:element :index |
		(element notNil and: [element ~= flag]) ifTrue: [
			elementAndIndexBlock
				value: element
				value: index]].! !


!WeakSetInspectorTest methodsFor: 'tests' stamp: 'ct 1/4/2020 01:25'!
testSymbolTableM6812
	"this test is related to http://bugs.squeak.org/view.php?id=6812"
	
	| aWeakSet anInspector fieldSize |
	aWeakSet := (Symbol classPool at: #SymbolTable).
	anInspector := aWeakSet inspectorClass on: aWeakSet.
	
	fieldSize := anInspector fieldList size.
	Smalltalk garbageCollect.
	self assert: fieldSize equals: anInspector fieldList size.! !

!WeakSetInspectorTest methodsFor: 'accessing' stamp: 'ct 1/4/2020 01:24'!
createTarget

	| weakSet |
	weakSet := WeakSet withAll: {Smalltalk. Object. true}.
	Smalltalk garbageCollect.
	^ weakSet! !

WeakSetInspector removeSelector: #fieldList!
WeakSetInspector removeSelector: #initialize!
SetInspector subclass: #WeakSetInspector
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Tools-Inspector'!
SetInspector removeSelector: #arrayIndexForSelection!
SetInspector removeSelector: #copyName!
SetInspector removeSelector: #fieldList!
SetInspector removeSelector: #mainFieldListMenu:!
SetInspector removeSelector: #removeSelection!
SetInspector removeSelector: #replaceSelectionValue:!
SetInspector removeSelector: #selection!
CompiledMethod removeSelector: #inspectorClass!
OrderedCollectionInspector removeSelector: #fieldList!
OrderedCollectionInspector removeSelector: #replaceSelectionValue:!
OrderedCollectionInspector removeSelector: #selectedObjectIndex!
OrderedCollectionInspector removeSelector: #selection!
InspectorBrowser removeSelector: #browser!
Model subclass: #InspectorBrowser
	instanceVariableNames: 'inspector browser'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Tools-Inspector'!
HtmlEntityInspector removeSelector: #fieldList!
HtmlEntityInspector removeSelector: #selection!
ExternalStructureInspector removeSelector: #fieldList!
ExternalStructureInspector removeSelector: #replaceSelectionValue:!
ExternalStructureInspector removeSelector: #selection!
DictionaryInspector removeSelector: #contentsIsString!
DictionaryInspector removeSelector: #copyName!
DictionaryInspector removeSelector: #fieldList!
DictionaryInspector removeSelector: #initialize!
DictionaryInspector removeSelector: #mainFieldListMenu:!
DictionaryInspector removeSelector: #numberOfFixedFields!
DictionaryInspector removeSelector: #replaceSelectionValue:!
DictionaryInspector removeSelector: #selection!
CollectionInspector subclass: #DictionaryInspector
	instanceVariableNames: 'keyArray'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Tools-Inspector'!
ContextVariablesInspector removeSelector: #contentsIsString!
ContextVariablesInspector removeSelector: #defaultIntegerBase!
ContextVariablesInspector removeSelector: #fieldList!
ContextVariablesInspector removeSelector: #inspect:!
ContextVariablesInspector removeSelector: #replaceSelectionValue:!
ContextVariablesInspector removeSelector: #selection!
ContextVariablesInspector removeSelector: #tempsAndValues!
Inspector subclass: #ContextVariablesInspector
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Tools-Debugger'!
ContextInspector removeSelector: #fieldList!
ContextInspector removeSelector: #selection!
CompiledMethodInspector removeSelector: #contentsIsString!
CompiledMethodInspector removeSelector: #fieldList!
CompiledMethodInspector removeSelector: #selection!
CompiledMethodInspector removeSelector: #selectionUnmodifiable!
Inspector removeSelector: #accept:!
Inspector removeSelector: #baseFieldList!
Inspector removeSelector: #chasePointers!
Inspector removeSelector: #convertToCurrentVersion:refStream:!
Inspector removeSelector: #defaultIntegerBase!
Inspector removeSelector: #defsOfSelection!
Inspector removeSelector: #explorePointers!
Inspector removeSelector: #inspectElement!
Inspector removeSelector: #referencesToSelection!
Inspector removeSelector: #setContents:!
Inspector removeSelector: #setContentsTyped:!
Inspector removeSelector: #trash!
Inspector removeSelector: #trash:!
Inspector removeSelector: #viewerForValue!
StringHolder subclass: #Inspector
	instanceVariableNames: 'object context fields customFields selectionIndex expression contentsTyped styler shouldStyleValuePane timeOfLastListUpdate selectionUpdateTime'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Tools-Inspector'!
HtmlEntity removeSelector: #inspect!
HtmlEntity removeSelector: #inspectWithLabel:!
"Postscript:"
Inspector allSubInstancesDo: [:inspector |
	(inspector instVarNamed: #customFields) ifNil: [
		inspector instVarNamed: #customFields put: OrderedCollection new]].!

