DictionaryInspectorView.st
author Claus Gittinger <cg@exept.de>
Mon, 20 Jan 2020 21:02:47 +0100
changeset 19422 c6ca1c3e0fd7
parent 19126 15cb6262ec30
permissions -rw-r--r--
#REFACTORING by exept class: MultiViewToolApplication added: #askForFile:default:forSave:thenDo: changed: #askForFile:default:thenDo: #askForFile:thenDo: #menuSaveAllAs #menuSaveAs

"
 COPYRIGHT (c) 1993 by Claus Gittinger
              All Rights Reserved

 This software is furnished under a license and may be used
 only in accordance with the terms of that license and with the
 inclusion of the above copyright notice.   This software may not
 be provided or otherwise made available to, or used by, any
 other person.  No title to or ownership of the software is
 hereby transferred.
"
"{ Package: 'stx:libtool' }"

"{ NameSpace: Smalltalk }"

InspectorView subclass:#DictionaryInspectorView
	instanceVariableNames:'keys hideClassVars hideClasses hideUnloadedClasses hideAliases
		hideNilValues hideLiteralValues hideColorsAndImages
		hideSignalInstances hideEmptyCollections hideFreeSemaphores
		hideCollectionsHoldingOnlyLiterals hideNonRefObjectReferences
		hideStreams hideFilenames hideSimpleObjects'
	classVariableNames:''
	poolDictionaries:''
	category:'Interface-Inspector'
!

!DictionaryInspectorView class methodsFor:'documentation'!

copyright
"
 COPYRIGHT (c) 1993 by Claus Gittinger
              All Rights Reserved

 This software is furnished under a license and may be used
 only in accordance with the terms of that license and with the
 inclusion of the above copyright notice.   This software may not
 be provided or otherwise made available to, or used by, any
 other person.  No title to or ownership of the software is
 hereby transferred.
"
!

documentation
"
    a modified Inspector for Dictionaries

    Notice the filters: these are to inspect Smalltalk,
    to get to interesting references more quickly 
    (typically to find class variables which still refer to object,
     keeping them from being collected)

    Try:
        Smalltalk inspect
    then enable some filter(s)
    
    [author:]
        Claus Gittinger
"
! !

!DictionaryInspectorView methodsFor:'event handling'!

keyPress:key x:x y:y
    "handle special keys"

    <resource: #keyboard (#Delete #BackSpace #Insert)>

    (key == #Delete or:[key == #BackSpace]) ifTrue:[
        self doRemoveKey.
        ^ self.
    ].
    (key == #Insert) ifTrue:[
        self doAddKey.
        ^ self.
    ].

    super keyPress:key x:x y:y
! !

!DictionaryInspectorView methodsFor:'initialization & release'!

initialize
    super initialize.

    listView multipleSelectOk:true.

    hideClassVars := false.
    hideClasses := false.
    hideUnloadedClasses := false.
    hideAliases := false.
    hideLiteralValues := false.
    hideNilValues := false.
    hideColorsAndImages := false.
    hideSignalInstances := false.
    hideEmptyCollections := false.
    hideFreeSemaphores := false.
    hideCollectionsHoldingOnlyLiterals := false.
    hideNonRefObjectReferences := false.
! !

!DictionaryInspectorView methodsFor:'menu'!

fieldMenu
    <resource: #programMenu >

    |items m selIdx|

    inspectedObject isNameSpace ifTrue:[
        items := #(
                       ('Copy Key'             doCopyKey      )
                       ('-')
                       ('Inspect'              doInspect      )
                       ('Inspect Key'          doInspectKey   )
                       ('BasicInspect'         doBasicInspect )
             ).
    NewInspector::NewInspectorView notNil ifTrue:[
        items := items , #(
                       ('Inspect Hierarchical'         #doNewInspect           )
                ).
    ].
    items := items , #(
                       ('-')
                       ('Owners'               showOwners     )
                       ('Ref Chains'           showReferences )
                       ('References to Global' showKeyReferences )
                       ('-')
                       ('Browse'               browse         )
                       ('-')
                       ('Add Key...'           doAddKey       )
                       ('Remove Key'           doRemoveKey    )
                       ('-')
                   ).

        items := items , #(
                       ('Show All'   doShowAll )
                       ('Hide All'   doHideAll )
                   ).

        hideClassVars == true ifTrue:[
            items := items , #(
                           ('Show ClassVars'   doShowClassVars )
                       ).
        ] ifFalse:[
            items := items , #(
                           ('Hide ClassVars'   doHideClassVars )
                       ).
        ].
        hideClasses == true ifTrue:[
            items := items , #(
                           ('Show Classes'     doShowClasses )
                       ).
        ] ifFalse:[
            items := items , #(
                           ('Hide Classes'     doHideClasses )
                       ).
        ].
        hideUnloadedClasses == true ifTrue:[
            items := items , #(
                           ('Show Unloaded Classes'     doShowUnloadedClasses )
                       ).
        ] ifFalse:[
            items := items , #(
                           ('Hide UnloadedClasses'     doHideUnloadedClasses )
                       ).
        ].
        hideAliases == true ifTrue:[
            items := items , #(
                           ('Show Aliases'     doShowAliases )
                       ).
        ] ifFalse:[
            items := items , #(
                           ('Hide Aliases'     doHideAliases )
                       ).
        ].
        hideLiteralValues == true ifTrue:[
            items := items , #(
                           ('Show Literal Values'  doShowLiteralValues )
                       ).
        ] ifFalse:[
            items := items , #(
                           ('Hide Literal Values'  doHideLiteralValues )
                       ).
        ].
        hideNilValues == true ifTrue:[
            items := items , #(
                           ('Show Nil Values'  doShowNilValues )
                       ).
        ] ifFalse:[
            items := items , #(
                           ('Hide Nil Values'  doHideNilValues )
                       ).
        ].
        hideColorsAndImages == true ifTrue:[
            items := items , #(
                           ('Show Colors and Images'  doShowColorsAndImages )
                       ).
        ] ifFalse:[
            items := items , #(
                           ('Hide Colors and Images'  doHideColorsAndImages )
                       ).
        ].
        hideSignalInstances == true ifTrue:[
            items := items , #(
                           ('Show Signals'  doShowSignalInstances )
                       ).
        ] ifFalse:[
            items := items , #(
                           ('Hide Signals'  doHideSignalInstances )
                       ).
        ].
        hideEmptyCollections == true ifTrue:[
            items := items , #(
                           ('Show Empty Collections'  doShowEmptyCollections )
                       ).
        ] ifFalse:[
            items := items , #(
                           ('Hide Empty Collections'  doHideEmptyCollections )
                       ).
        ].
        hideFreeSemaphores == true ifTrue:[
            items := items , #(
                           ('Show Free Semaphores'  doShowFreeSemaphores )
                       ).
        ] ifFalse:[
            items := items , #(
                           ('Hide Free Semaphores'  doHideFreeSemaphores )
                       ).
        ].
        hideStreams == true ifTrue:[
            items := items , #(
                           ('Show Streams'  doShowStreams )
                       ).
        ] ifFalse:[
            items := items , #(
                           ('Hide Streams'  doHideStreams )
                       ).
        ].
        hideFilenames == true ifTrue:[
            items := items , #(
                           ('Show Filenames'  doShowFilenames )
                       ).
        ] ifFalse:[
            items := items , #(
                           ('Hide Filenames'  doHideFilenames )
                       ).
        ].
        hideCollectionsHoldingOnlyLiterals == true ifTrue:[
            items := items , #(
                           ('Show Collections of Literals'  doShowCollectionsHoldingOnlyLiterals )
                       ).
        ] ifFalse:[
            items := items , #(
                           ('Hide Collections of Literals'  doHideCollectionsHoldingOnlyLiterals )
                       ).
        ].
        hideNonRefObjectReferences == true ifTrue:[
            items := items , #(
                           ('Show References to Simple Objects'  doShowNonRefObjectReferences )
                       ).
        ] ifFalse:[
            items := items , #(
                           ('Hide References to Simple Objects'  doHideNonRefObjectReferences )
                       ).
        ].

    ] ifFalse:[
        items := #(
                       ('Copy Key'             doCopyKey      )
                       ('-')
                       ('Inspect'              doInspect      )
                       ('Inspect Key'          doInspectKey   )
                       ('BasicInspect'         doBasicInspect )
                       ('Inspect Hierarchical' doNewInspect   )
                       ('-')
                       ('Owners'               showOwners     )
                       ('Ref Chains'           showReferences )
                       ('Ref Chains to Key'    showReferencesToKey )
                       ('-')
                       ('Browse'                       browse                 )
                       ('Browse Class Hierarchy'       browseClassHierarchy   )
                       ('Browse Full Class Protocol'   browseFullClassProtocol)
                       ('-')
                       ('Add Key...'           doAddKey       )
                       ('Remove Key'           doRemoveKey    )
                   ).
    ].

    (hasMore) ifTrue:[
        items := items , #(                                  
                      ('-')
                      ('Show More'                   showMore               )
                   ).
        (inspectedObject size > (nShown * 2)) ifTrue:[
            items := items , #(
                        ('Show All'                     #showAll                )
                          )
        ].
    ].
    monitorProcess isNil ifTrue:[
        items := items , #(
                       ('-')
                       ('Start Monitor'    doStartMonitor )
                          ).
    ] ifFalse:[
        items := items , #(
                       ('-')
                       ('Stop Monitor'     doStopMonitor  )
                          ).
    ].

    items := items , (self sortOrderItems).
    items := items , #(
                   ('-')
                   ('Update'     doUpdate  )
                      ).

    m := PopUpMenu itemList:items resources:resources.

    (inspectedObject isNameSpace or:[inspectedObject isSharedPool]) ifTrue:[
        m disableAll:#( doAddKey )
    ].
    (inspectedObject isSharedPool) ifTrue:[
        m disableAll:#( doRemoveKey )
    ].

    (selIdx := self theSingleSelectionIndex) isNil ifTrue:[
        m disableAll:#(doInspect doInspectKey doBasicInspect doNewInspect
                       doStartMonitor doStopMonitor doCopyKey 
                       showKeyReferences showReferences showOwners browse
                      ).
        selectionIndex isEmptyOrNil ifTrue:[
            "/ allowed for multi-select
            m disableAll:#( doRemoveKey )
        ]
    ] ifFalse:[
        (self keyIndexForLine:selIdx) isNil ifTrue:[
            m disableAll:#(doInspectKey doRemoveKey doCopyKey)
        ]
    ].
    hideLiteralValues == true ifTrue:[
        m disableAll:#( doShowNilValues doHideNilValues )
    ].

    ^ m.

    "Modified: / 26-09-2012 / 13:20:59 / cg"
    "Modified: / 31-07-2018 / 01:14:46 / Claus Gittinger"
! !

!DictionaryInspectorView methodsFor:'menu actions'!

browse
    |cls|

    cls := self selection class theNonMetaclass.
"/    cls isNameSpace ifTrue:[
"/        self halt.
"/    ].
    cls browserClass openInClass:cls selector:nil
!

doAddKey
    "add a key"

    |keyName key val l|

    keyName := Dialog request:'Key to add (storeString):' initialAnswer:''.
    keyName notEmptyOrNil ifTrue:[
        key := Object readFrom:keyName onError:[ self information:'Bad input.'. ^ self].
        (inspectedObject includesKey:key) ifFalse:[
            val := Dialog request:'Value to add (storeString):' initialAnswer:''.
            val notNil ifTrue:[
                val := Object readFrom:val onError:[ self information:'Bad input.'. ^ self].
            ].

            inspectedObject at:key put:val.
            selectionIndex := selectedLine := nil.
            inspectedObject changed.
            l := listView firstLineShown.
            self reinspect. "force list update"
            listView scrollToLine:l
        ]
    ]

    "Modified: / 01-07-2010 / 10:53:25 / cg"
!

doHideAliases
    hideAliases := true.
    self reinspect
!

doHideAll
    "/ hideClassVars := true.   
    hideClasses := hideUnloadedClasses := hideAliases := true.
    hideNilValues := hideLiteralValues := hideColorsAndImages := true.
    hideSignalInstances := hideEmptyCollections := hideFreeSemaphores := true.
    hideCollectionsHoldingOnlyLiterals := hideNonRefObjectReferences := true.
    hideStreams := hideFilenames := hideSimpleObjects := true.
    hideAliases := true.
    self reinspect

    "Created: / 31-07-2018 / 01:16:07 / Claus Gittinger"
!

doHideClassVars
    hideClassVars := true.
    self reinspect
!

doHideClasses
    hideClasses := true.
    self reinspect
!

doHideCollectionsHoldingOnlyLiterals
    hideCollectionsHoldingOnlyLiterals := true.
    self reinspect
!

doHideColorsAndImages
    hideColorsAndImages := true.
    self reinspect
!

doHideEmptyCollections
    hideEmptyCollections := true.
    self reinspect
!

doHideFilenames
    hideFilenames := true.
    self reinspect

    "Created: / 31-07-2018 / 01:13:51 / Claus Gittinger"
!

doHideFreeSemaphores
    hideFreeSemaphores := true.
    self reinspect
!

doHideLiteralValues
    hideLiteralValues := true.
    self reinspect
!

doHideNilValues
    hideNilValues := true.
    self reinspect
!

doHideNonRefObjectReferences
    hideNonRefObjectReferences := true.
    self reinspect
!

doHideSignalInstances
    hideSignalInstances := true.
    self reinspect
!

doHideSimpleObjects
    hideSimpleObjects := true.
    self reinspect

    "Created: / 31-07-2018 / 01:29:29 / Claus Gittinger"
!

doHideStreams
    hideStreams := true.
    self reinspect

    "Created: / 31-07-2018 / 01:13:18 / Claus Gittinger"
!

doHideUnloadedClasses
    hideUnloadedClasses := true.
    self reinspect
!

doInspectKey
    "inspect selected items key"

    |key|

    key := self selectedKey.
    key notNil ifTrue:[
        self inspectNext:key.
    ]
!

doRemoveKey
    "remove selected item from keys"

    |l|

    listView withWaitCursorDo:[
        self selectedKeys do:[:key |
            (inspectedObject includesKey:key) ifTrue:[
                inspectedObject removeKey:key
            ]
        ].

        keys := nil.
        selectionIndex := selectedLine := nil.
        inspectedObject changed.
    ].

    l := listView firstLineShown.
    self reinspect. "force list update"
    listView scrollToLine:l.
!

doShowAliases
    hideAliases := false.
    self reinspect
!

doShowAll
    "/ hideClassVars := := false.
    hideClasses := hideUnloadedClasses := hideAliases := false.
    hideNilValues := hideLiteralValues := hideColorsAndImages := false.
    hideSignalInstances := hideEmptyCollections := hideFreeSemaphores := false.
    hideCollectionsHoldingOnlyLiterals := hideNonRefObjectReferences := false.
    hideStreams := hideFilenames := false.
    hideAliases := hideSimpleObjects := false.
    self reinspect

    "Created: / 31-07-2018 / 01:16:17 / Claus Gittinger"
!

doShowClassVars
    hideClassVars := false.
    self reinspect
!

doShowClasses
    hideClasses := false.
    self reinspect
!

doShowCollectionsHoldingOnlyLiterals
    hideCollectionsHoldingOnlyLiterals := false.
    self reinspect
!

doShowColorsAndImages
    hideColorsAndImages := false.
    self reinspect
!

doShowEmptyCollections
    hideEmptyCollections := false.
    self reinspect
!

doShowFilenames
    hideFilenames := false.
    self reinspect

    "Created: / 31-07-2018 / 01:13:41 / Claus Gittinger"
!

doShowFreeSemaphores
    hideFreeSemaphores := false.
    self reinspect
!

doShowLiteralValues
    hideLiteralValues := false.
    self reinspect
!

doShowNilValues
    hideNilValues := false.
    self reinspect
!

doShowNonRefObjectReferences
    hideNonRefObjectReferences := false.
    self reinspect
!

doShowSignalInstances
    hideSignalInstances := false.
    self reinspect
!

doShowSimpleObjects
    hideSimpleObjects := false.
    self reinspect

    "Created: / 31-07-2018 / 01:29:43 / Claus Gittinger"
!

doShowStreams
    hideStreams := false.
    self reinspect

    "Created: / 31-07-2018 / 01:13:27 / Claus Gittinger"
!

doShowUnloadedClasses
    hideUnloadedClasses := false.
    self reinspect
!

showKeyReferences
    "show users of selected key (i.e. global).
     Only useful when inspecting smalltalk"

    |key|

    key := self selectedKey.
    key notNil ifTrue:[
        self topView withWaitCursorDo:[
            SystemBrowser default browseReferendsOf:(key asSymbol)
        ].
    ]

    "Modified: / 01-09-2017 / 14:20:41 / cg"
!

showReferencesToKey
    self selectedKey class hasImmediateInstances ifTrue:[
        ^ self warn:'Sorry - cannot show references to immediate objects'
    ].
    "Run in own process to allow inspector to be closed while running"
    [
        ObjectMemory displayRefChainTo:(self selectedKey)
    ] fork.

    "Modified: / 13-02-2018 / 12:27:39 / stefan"
! !

!DictionaryInspectorView methodsFor:'private'!

baseInspectedObjectClass
    "only instvars below that are shown by me in the non-basic tab.
     This hides uninterresting details in the regular tab"

    (inspectedObject isKindOf:Dictionary) ifTrue:[
        ^ Dictionary
    ].
    (inspectedObject isKindOf:SmallDictionary) ifTrue:[
        ^ SmallDictionary
    ].
    "this is true for e.g. MethodDictionary"
    ^ Object

    "Modified: / 23.7.1999 / 10:39:11 / stefan"
!

defaultLabel
    ^ 'Keys'

    "Created: 28.6.1996 / 19:46:51 / cg"
!

hasAllNumericKeys
    "answer true, if all keys of the inspectedObject are numbers"

    inspectedObject keysDo:[:k | 
        k isProtoObject ifTrue:[^ false].
        k isNumber ifFalse:[^ false].
    ].
    ^ true

    "Created: / 03-04-2019 / 08:23:56 / Claus Gittinger"
!

indexList
    "return a list of indexes to show in the selectionList.
     Set hasMore to true, if a '...' entry should be added."

    |sortBlockForKeys allShown|

    (inspectedObject isNameSpace 
     or:[inspectedObject isSharedPool]) ifTrue:[
        ^ self indexListForNameSpace.
    ].

    allShown := inspectedObject size <= nShown.

    inspectedObject isOrdered ifFalse:[
        (allShown and:[self hasAllNumericKeys]) ifTrue:[
            sortBlockForKeys := [:a :b | a < b].
        ] ifFalse:[
            sortBlockForKeys := [:a :b | a displayString < b displayString].
        ].
    ].

    sortBlockForKeys notNil ifTrue:[
        keys := (SortedCollection new:(inspectedObject size min:nShown)) sortBlock:sortBlockForKeys.
    ] ifFalse:[
        keys := OrderedCollection new:(inspectedObject size min:nShown).
    ].

    "/ do not use 'inspectedObject keys',
    "/ since Sets couldn't hold nils (which are now valid keys)
    "/ now they can: #(1 2 3 nil) asSet
    allShown ifTrue:[
        inspectedObject keysDo:[:k | keys add:k].
        ^ keys.
    ].

    inspectedObject keysDo:[:k | 
        keys add:k.
        keys size >= nShown ifTrue:[ 
            hasMore := true.
            ^ keys
        ].
    ]. 
    ^ keys.

    "Modified: / 10-05-2011 / 08:14:59 / cg"
    "Modified (comment): / 02-04-2019 / 23:21:09 / Stefan Vogel"
!

indexListForNameSpace
    "return a list of indexes to show in the selectionList.
     Set hasMore to true, if a '...' entry should be added."

    keys := SortedCollection new:1000.

    inspectedObject keysDo:[:k |
        |hidden i o|

        hidden := false.
        hideClassVars == true ifTrue:[
            (i := k lastIndexOf:$:) ~~ 0 ifTrue:[
                (i > 1 and:[(k at:i-1) ~~ $:]) ifTrue:[
                    hidden := true
                ].
            ].
        ].
        (hidden not and:[hideNilValues == true]) ifTrue:[
            o isNil ifTrue:[ 
                o := inspectedObject at:k ifAbsent:nil. 
                o isNil ifTrue:[
                    hidden := true
                ].
            ].
        ].
        (hidden not and:[hideClasses == true]) ifTrue:[
            o isNil ifTrue:[ o := inspectedObject at:k ifAbsent:nil ].
            o isBehavior ifTrue:[
                inspectedObject == Smalltalk ifTrue:[
                    o name == k ifTrue:[
                        hidden := true
                    ]
                ] ifFalse:[
                    o nameWithoutNameSpacePrefix = k ifTrue:[
                        hidden := true
                    ]
                ]
            ].
        ].
        (hidden not and:[hideAliases == true]) ifTrue:[
            o isNil ifTrue:[ o := inspectedObject at:k ifAbsent:nil ].
            o isBehavior ifTrue:[
                inspectedObject == Smalltalk ifTrue:[
                    o name ~~ k ifTrue:[
                        hidden := true
                    ]
                ] ifFalse:[
                    o nameWithoutNameSpacePrefix ~= k ifTrue:[
                        hidden := true
                    ].
                ].
            ].
        ].
        (hidden not and:[hideLiteralValues == true]) ifTrue:[
self breakPoint:#cg.
            o isNil ifTrue:[ o := inspectedObject at:k ifAbsent:nil ].
            o isLiteral ifTrue:[
                hidden := true
            ].
        ].
        (hidden not and:[hideColorsAndImages == true]) ifTrue:[
            o isNil ifTrue:[ o := inspectedObject at:k ifAbsent:nil ].
            (o isColor or:[o isImageOrForm or:[o class == Cursor]]) ifTrue:[
                hidden := true
            ].
        ].
        (hidden not and:[hideSignalInstances == true]) ifTrue:[
            o isNil ifTrue:[ o := inspectedObject at:k ifAbsent:nil ].
            (o isException or:[o isKindOf:Signal]) ifTrue:[
                hidden := true
            ].
        ].
        (hidden not and:[hideEmptyCollections == true]) ifTrue:[
            o isNil ifTrue:[ o := inspectedObject at:k ifAbsent:nil ].
            (o isCollection and:[o size == 0]) ifTrue:[
                hidden := true
            ].
        ].                   
        (hidden not and:[hideCollectionsHoldingOnlyLiterals == true]) ifTrue:[
            o isNil ifTrue:[ o := inspectedObject at:k ifAbsent:nil ].
            (o isCollection) ifTrue:[
                (o conform:[:el | el isLiteral]) ifTrue:[
                    hidden := true
                ] ifFalse:[
                    (o conform:[:el | el isCollection and:[el conform:[:subEl | subEl isLiteral]]]) ifTrue:[
                        hidden := true
                    ].
                ].
            ].
        ].                   
        (hidden not and:[hideFreeSemaphores == true]) ifTrue:[
            o isNil ifTrue:[ o := inspectedObject at:k ifAbsent:nil ].
            ((o isKindOf:Semaphore) 
                    and:[(o owner isNil or:[o owner isCollection and:[o owner isEmpty]])
                    and:[o waitingProcesses isEmptyOrNil]]) ifTrue:[
                hidden := true
            ].
        ].
        (hidden not and:[hideNonRefObjectReferences == true]) ifTrue:[
            o isNil ifTrue:[ o := inspectedObject at:k ifAbsent:nil ].
            hidden := (o class == Point)
                         or:[(o class == Rectangle)
                         or:[(o class == Object)]]
        ].
        (hidden not and:[hideFilenames == true]) ifTrue:[
            o isNil ifTrue:[ o := inspectedObject at:k ifAbsent:nil ].
            (o isFilename) ifTrue:[
                hidden := true
            ].
        ].
        (hidden not and:[hideStreams == true]) ifTrue:[
            o isNil ifTrue:[ o := inspectedObject at:k ifAbsent:nil ].
            (o isStream) ifTrue:[
                hidden := true
            ].
        ].
        (hidden not and:[hideSimpleObjects == true]) ifTrue:[
            o isNil ifTrue:[ o := inspectedObject at:k ifAbsent:nil ].
            ((1 to:o class instSize) conform:[:i | (o instVarAt:i) isLiteral]) ifTrue:[
                ((o basicSize == 0)
                or:[ ((1 to:o basicSize) conform:[:i | (o basicAt:i) isLiteral]) ]) ifTrue:[
                    hidden := true
                ].
            ].
        ].

        hidden ifFalse:[keys add:k]
    ].
    ^ keys

    "Modified: / 31-01-2018 / 09:34:39 / stefan"
    "Modified: / 31-07-2018 / 01:36:29 / Claus Gittinger"
!

indexedFieldList 
    "return a list of indexed-variable names to show in the selectionList.
     Set hasMore to true, if a '...' entry should be added."

    |indexList keyList|

    indexList := self indexList.
    keyList := indexList 
        collect:[:k | 
            (k isProtoObject not and:[k isInteger])  
                ifTrue:[ self basicDisplayStringForValue:k ] 
                ifFalse:[ k displayString ]
        ].

    sortOrder == SortOrderAlphabetical ifTrue:[
        keyList sort:[:a :b | a string < b string].
    ].
    ^ keyList
        keysAndValuesCollect:[:idx :nm |
            self listEntryForName:nm value:(self indexedValueAtKey:(indexList at:idx))
        ].

    "Modified: / 26-09-2012 / 13:22:08 / cg"
    "Modified: / 25-07-2014 / 09:44:34 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 31-01-2018 / 09:03:51 / stefan"
!

indexedValueAtKey:key
    object isWeakCollection ifTrue:[
        "keys may vanish"
        ^ object at:key ifAbsent:[].
    ].
    ^ object at:key ifAbsent:NoLongerPresentDummyObject

    "Modified: / 06-08-2019 / 18:25:52 / Stefan Vogel"
!

instVarIndexForLine:lineNr
    "helper - return the index for a named instVar;
     nil, if self or a keyed instvar is selected."

    (inspectedObject isNameSpace or:[inspectedObject isSharedPool]) ifTrue:[
        ^ nil
    ].
    ^ super instVarIndexForLine:lineNr
!

keyIndexForLine:lineNr
    "helper - return the index of the key-list"

    |firstRealIndex idx line|

    (inspectedObject isNameSpace or:[inspectedObject isSharedPool]) ifTrue:[
        (self hasSelfEntry
        and:[lineNr == 1 or:[lineNr isNil]]) ifTrue:[
            ^ nil "/ self selected
        ].
        firstRealIndex := 1.
        idx := lineNr.
        [line := self listEntryAt:firstRealIndex. 
         (line startsWith:'-') and:[line size < 2 or:[line second isDigit not]]] whileTrue:[
            firstRealIndex := firstRealIndex + 1.
            idx := idx - 1.
        ].

        ^ idx   
    ].
    ^ super keyIndexForLine:lineNr

    "Modified: / 16-05-2012 / 17:56:01 / cg"
!

namedFieldList 
    "return a list of instVar names to show in the selectionList."

    (inspectedObject isNameSpace or:[inspectedObject isSharedPool]) ifTrue:[
        "/ empty ...
        ^ OrderedCollection new
    ].
    ^ super namedFieldList
!

numIndexedFields
    ^ inspectedObject size
!

release 
    "release inspected object"

    keys := nil.
    super release
!

selectedKey
    "selected item's key or nil. But only if exactly one item is selected"

    |selIdx idx|

    selIdx := self theSingleSelectionIndex.
    selIdx notNil ifTrue:[
        idx := self keyIndexForLine:selIdx.
        idx notNil ifTrue:[
            ^ (keys at:idx)
        ].
    ].
    ^ nil.
!

selectedKeys
    "selected keys or empty"

    ^ (listView selection ? #()) 
        collect:[:eachSelectionIndex |
            |idx|

            idx := self keyIndexForLine:eachSelectionIndex.
            idx notNil 
                ifTrue:[ (keys at:idx) ]
                ifFalse:[ nil ]
        ]
        thenSelect:[:each | each notNil].

    "Modified: / 01-07-2010 / 10:54:31 / cg"
!

selection:lineNrCollection
    "redefined because of multiselect"

    lineNrCollection isEmptyOrNil ifTrue:[
        self showSelection:nil
    ] ifFalse:[
        self showSelection:lineNrCollection first
    ].
! !

!DictionaryInspectorView methodsFor:'user interaction'!

indexedValueAtIndex:idx
    |key|

    key := keys at:idx ifAbsent:[^ nil].
    ^ inspectedObject at:key ifAbsent:NoLongerPresentDummyObject.

    "Modified: / 06-08-2019 / 18:53:27 / Stefan Vogel"
!

indexedValueAtIndex:idx put:newValue
    |key|

    key := keys at:idx.
    inspectedObject at:key put:newValue.
! !

!DictionaryInspectorView class methodsFor:'documentation'!

version
    ^ '$Header$'
!

version_CVS
    ^ '$Header$'
! !