"======================================================================
|
|   Smalltalk GUI inspector for Dictionaries
|
|   $Revision: 1.7.5$
|   $Date: 2000/05/28 16:56:52$
|   $Author: pb$
|
 ======================================================================"


"======================================================================
|
| Copyright 1988-92, 1994-95, 1999, 2000 Free Software Foundation, Inc.
| Written by Brad Diller.
|
| This file is part of GNU Smalltalk.
|
| GNU Smalltalk is free software; you can redistribute it and/or modify it
| under the terms of the GNU General Public License as published by the Free
| Software Foundation; either version 2, or (at your option) any later version.
| 
| GNU Smalltalk is distributed in the hope that it will be useful, but WITHOUT
| ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
| FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
| details.
| 
| You should have received a copy of the GNU General Public License along with
| GNU Smalltalk; see the file COPYING.  If not, write to the Free Software
| Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  
|
 ======================================================================
"

GenericInspector subclass:  #DictionaryInspector
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Graphics-Browser'
!

!DictionaryInspector methodsFor: 'initializing'!

inspectMenu: listView
"Initialize menu for variable list pane"
    ^((PopupMenu new: listView label: '') selectors:
#(('Inspect' evalAndInspectResult: listView) ('References' references: listView) 
() ('Add key...' addField: listView) ('Remove...' removeField: listView))
					  receiver: self
					  argument: listView ).
! !

!DictionaryInspector methodsFor: 'private'!

currentVariableValue
    currentVariable == 0
	ifTrue: [ ^nil ].
    ^(theObject at: currentVariable)
!

currentVariable: obj
    theObject at: currentVariable put: obj.
!

instVarsSortBlock
    ^[ :a :b | (a isNil or: [ b isNil ])
	ifTrue: [ true ]
	ifFalse: [ a key <= b key ] ].
!

setInstanceVars: anObject
"Initialize instance variable, instVars, which governs display of
variable list pane.  Since the dictionary keys can be non-symbols as
well as symbols, it is not the case that the string representation of
the key will uniquely identify the dictionary entry.  Consequently,
the Association (dictionary entry) consisting of the key and value is
stored in the SortedCollection variable, instVars.  Using this
approach, we can pick out the Dictionary key's unique value by using
the selected list element's number as a key into instVars which is a
SortedCollection of Associations."
    theObject := anObject.
    theObject keysDo:
	[ :aKey | instVars add:  (Association key: (aKey displayString) 
					      value: aKey)].
! !

!DictionaryInspector methodsFor: 'accessing'!

variable: assoc
"Set list selection to value of index.  Force a text view update"
    assoc key == 0
	ifTrue: [ currentVariable := 0 ]
	ifFalse: [currentVariable := (instVars at: assoc key) value].
    self changeState: #text.
    Primitive updateViews.
!

variableList
"Return sorted list of keys from set of Associations stored in instVars"
    ^instVars inject: (SortedCollection new) into: [:col :each | col add: each 
								     key; yourself ].
! !

!DictionaryInspector methodsFor: 'variable list menu'!

addField: listView
"Prompt user for the name of new dictionary key.  If name is valid, add it
to dictionary"
    | key |
    listView canChangeState ifFalse: [^self].
    key := (Prompter message: 'Enter a new field' in: listView) response.
    key isEmpty ifTrue: [ ^self ].
    key isNumeric ifTrue: [ key := key asNumber ].
    (key at: 1) == $# ifTrue: [ key := (key copyFrom: 2 to: key size) asSymbol ].

    "If new key already exists, reject "
    (theObject includesKey: key ) ifTrue: [
	^ModalDialog new
	    alertMessage: 'Invalid name: the key, ' , key, ', already exists.' 
	    in: listView
    ].

    "Update variable selection"     
    currentVariable := key.
    "Update dictionary"
    theObject at: key put: nil.
    "Update instance variable governing variable list pane display"
    instVars add: (Association key: key displayString value: key).
    "Update text view"
    self changeState: #variableList;
	changeState: #text.
    Primitive updateViews.
!

references: listView
"Open a method set browser on all methods which reference selected key"
    | alert keyRefs theKey |
    currentVariable isNil ifTrue: [^listView beep].
    keyRefs := SortedCollection new.
    Namespace current allClassObjectsDo: 
	[:subclass | (subclass whichSelectorsReferTo: 
			  (theObject associationAt: currentVariable)) do: 
			      [ :sel | keyRefs add: ( subclass printString , ' ', sel )]].
    keyRefs isEmpty ifTrue: [^alert := ModalDialog new alertMessage: 
				 'No references to ', (currentVariable printString) in: listView]. 
    MethodSetBrowser new openOn: keyRefs title: 'References to ', 
	(currentVariable printString)  selection: (currentVariable displayString).
!

removeField: listView
| cancel |
    "Remove selected key from dictionary"
    currentVariable isNil ifTrue: [^listView beep].
     ModalDialog new message: ('Are you sure you want to remove, ', 
	  currentVariable, '?') in: listView;
     addButton: 'Yes' message: [cancel := false];
     addButton: 'No' message: [cancel := true];
     display: listView.
     cancel ifTrue: [^self].
    "Remove key from dictionary"
    theObject removeKey: currentVariable.
    "Remove the association composed of the key and the value from the data object"
    instVars remove: (Association key: currentVariable value: currentVariable).
    currentVariable := 0.
    "Force a text view update to reflect deleted key"
    self changeState: #variableList;
	changeState: #text.
    Primitive updateViews.
! !

! Dictionary methodsFor: 'debugging' !

inspect
"Open a DictionaryInspector window on self"
    DictionaryInspector new openOn: self
!

inspect: pane
"Open a DictionaryInspector window on self"
    DictionaryInspector new openOn: self in: pane
! !
