UIHelpTool.st
author Patrik Svestka <patrik.svestka@gmail.com>
Wed, 14 Nov 2018 12:07:51 +0100
branchjv
changeset 3630 5e718e0a754e
parent 3362 177a52729a22
child 3392 ade42ddd74fe
permissions -rw-r--r--
Issue #239: Fix all Smalltak/X source files to be in unicode (UTF8 without BOM) and prefixed by "{ Encoding: utf8 }" when any unicode character is present

- All source *.st files are now Unicode UTF8 without BOM
Files are in two groups (fileOut works this way in Smalltalk/X):
- containing a unicode character have "{ Encoding: utf8 }" at the header
- ASCII only are without the header
     1 "
     2  COPYRIGHT (c) 1995 by eXept Software AG
     3 	      All Rights Reserved
     4 
     5  This software is furnished under a license and may be used
     6  only in accordance with the terms of that license and with the
     7  inclusion of the above copyright notice.   This software may not
     8  be provided or otherwise made available to, or used by, any
     9  other person.  No title to or ownership of the software is
    10  hereby transferred.
    11 "
    12 "{ Package: 'stx:libtool2' }"
    13 
    14 "{ NameSpace: Smalltalk }"
    15 
    16 ResourceSpecEditor subclass:#UIHelpTool
    17 	instanceVariableNames:'classItemList classItemModel keyItemModel helpTextView
    18 		modifiedHolder contentsModifiedChannel editModel'
    19 	classVariableNames:''
    20 	poolDictionaries:''
    21 	category:'Interface-UIPainter'
    22 !
    23 
    24 HierarchicalItem subclass:#ClassItem
    25 	instanceVariableNames:'theClass list modified'
    26 	classVariableNames:''
    27 	poolDictionaries:''
    28 	privateIn:UIHelpTool
    29 !
    30 
    31 HierarchicalItem subclass:#KeyItem
    32 	instanceVariableNames:'helpKey helpText flyByText modified icon'
    33 	classVariableNames:''
    34 	poolDictionaries:''
    35 	privateIn:UIHelpTool
    36 !
    37 
    38 !UIHelpTool class methodsFor:'documentation'!
    39 
    40 copyright
    41 "
    42  COPYRIGHT (c) 1995 by eXept Software AG
    43 	      All Rights Reserved
    44 
    45  This software is furnished under a license and may be used
    46  only in accordance with the terms of that license and with the
    47  inclusion of the above copyright notice.   This software may not
    48  be provided or otherwise made available to, or used by, any
    49  other person.  No title to or ownership of the software is
    50  hereby transferred.
    51 "
    52 !
    53 
    54 documentation
    55 "
    56     The Help Tool allows you to define help dictionaries for the widgets in
    57     window applications. The tool are able to run stand alone or in other master 
    58     applications like the GUI Painter and the Menu Editor.
    59     If the application responds to the selector #showHelp:aHelpText for:aView,
    60     this selector is called by the widget's view when the mouse cursor moves over. 
    61     If the application does not responds to that selector, and the activeHelp mode
    62     is enabled, an active help bubble is shown at the widget's view.
    63 
    64     [instance variables:]
    65 	specClass       <Symbol>        class implementing the help spec
    66 	specSelector    <Symbol>        selector returning the help spec
    67 	classItemList                   the list of classItems
    68 	classItemModel                  keeps the selected class
    69 	keyItemModel                    keeps the selected helpKey
    70 	modifiedHolder  <ValueHolder>   true if the editField or contents changed
    71 	editModel                       keeps the current helpKey
    72 	helpTextView                    the view which shows the helpText
    73 	contentsModifiedChannel         true if the helpText is modified
    74 
    75     [author:]
    76 	Claus Atzkern, eXept Software AG
    77 	Thomas Zwick,  eXept Software AG
    78 "
    79 ! !
    80 
    81 !UIHelpTool class methodsFor:'instance creation'!
    82 
    83 open
    84     ^ self openOnClass:nil.
    85 !
    86 
    87 openOnClass:aClass
    88     "opens a Help Tool on aClass
    89     "
    90     ^ self openOnClass:aClass andSelector:#helpSpec
    91 ! !
    92 
    93 !UIHelpTool class methodsFor:'constants'!
    94 
    95 label
    96     "returns the label; used if embedded as sub canvas in the GUI Painter or Menu Editor
    97     "
    98     ^'Help'
    99 ! !
   100 
   101 !UIHelpTool class methodsFor:'defaults'!
   102 
   103 resourceType
   104     "get the type of the resource of the method generated by the UIHelpTool"
   105 
   106     ^ #help
   107 ! !
   108 
   109 !UIHelpTool class methodsFor:'help specs'!
   110 
   111 flyByHelpSpec
   112     "This resource specification was automatically generated
   113      by the UIHelpTool of ST/X."
   114 
   115     "Do not manually edit this!! If it is corrupted,
   116      the UIHelpTool may not be able to read the specification."
   117 
   118     "
   119      UIHelpTool openOnClass:UIHelpTool    
   120     "
   121 
   122     <resource: #help>
   123 
   124     ^ super flyByHelpSpec addPairsFrom:#(
   125 
   126 #addHelpTextKey
   127 'Adds the key to the help spec.'
   128 
   129 #currentHelpTexts
   130 'Selected help text key.'
   131 
   132 #deleteHelpTextKey
   133 'Deletes the key from the help spec.'
   134 
   135 #fileLoad
   136 'Opens a dialog for selecting and loading a help spec from a class.'
   137 
   138 #fileSave
   139 'Saves the current help spec.'
   140 
   141 #fileUpdate
   142 'Reload the help spec.'
   143 
   144 #helpTextView
   145 'Shows the help text. Menu action ''Accept'' commits changes'
   146 
   147 #listOfClasses
   148 'Classes where help specs can be/are implemented.'
   149 
   150 #listOfHelpTexts
   151 'List of help text keys.'
   152 
   153 #removeHelpTextKey
   154 'Removes the help message from the widget.'
   155 
   156 #updateHelpTextKey
   157 'Refetch the help spec.'
   158 
   159 )
   160 ! !
   161 
   162 !UIHelpTool class methodsFor:'interface specs'!
   163 
   164 innerSpec
   165     "This resource specification was automatically generated
   166      by the UIPainter of ST/X."
   167 
   168     "Do not manually edit this!! If it is corrupted,
   169      the UIPainter may not be able to read the specification."
   170 
   171     "
   172      UIPainter new openOnClass:UIHelpTool andSelector:#innerSpec
   173      UIHelpTool new openInterface:#innerSpec
   174     "
   175 
   176     <resource: #canvas>
   177 
   178     ^ 
   179      #(FullSpec
   180         name: innerSpec
   181         window: 
   182        (WindowSpec
   183           label: 'UIHelpTool'
   184           name: 'UIHelpTool'
   185           min: (Point 10 10)
   186           bounds: (Rectangle 0 0 461 293)
   187         )
   188         component: 
   189        (SpecCollection
   190           collection: (
   191            (VariableVerticalPanelSpec
   192               name: 'PanelVrt'
   193               layout: (LayoutFrame 0 0.0 0 0.0 0 1.0 0 1.0)
   194               component: 
   195              (SpecCollection
   196                 collection: (
   197                  (VariableHorizontalPanelSpec
   198                     name: 'PanelHrz'
   199                     component: 
   200                    (SpecCollection
   201                       collection: (
   202                        (HierarchicalListViewSpec
   203                           name: 'keyItemModel'
   204                           model: keyItemModel
   205                           menu: keyItemMenu
   206                           hasHorizontalScrollBar: true
   207                           hasVerticalScrollBar: true
   208                           miniScrollerHorizontal: true
   209                           miniScrollerVertical: false
   210                           listModel: keyItemListHolder
   211                           useIndex: false
   212                           highlightMode: label
   213                           showLines: false
   214                           showIndicators: false
   215                           showLeftIndicators: false
   216                           useDefaultIcons: false
   217                           autoScrollHorizontal: false
   218                         )
   219                        (ViewSpec
   220                           name: 'classItemList'
   221                           component: 
   222                          (SpecCollection
   223                             collection: (
   224                              (InputFieldSpec
   225                                 name: 'editModel'
   226                                 layout: (LayoutFrame 0 0.0 2 0 -1 1.0 25 0)
   227                                 activeHelpKey: currentHelpTexts
   228                                 model: editModel
   229                                 immediateAccept: true
   230                                 acceptOnReturn: false
   231                                 acceptOnTab: false
   232                                 acceptOnLostFocus: false
   233                                 acceptOnPointerLeave: false
   234                               )
   235                              (SelectionInListModelViewSpec
   236                                 name: 'classItemModel'
   237                                 layout: (LayoutFrame 0 0.0 27 0.0 0 1.0 0 1.0)
   238                                 model: classItemModel
   239                                 hasHorizontalScrollBar: true
   240                                 hasVerticalScrollBar: true
   241                                 miniScrollerHorizontal: true
   242                                 miniScrollerVertical: true
   243                                 autoHideScrollBars: false
   244                                 listModel: classItemListHolder
   245                                 useIndex: false
   246                                 highlightMode: label
   247                               )
   248                              )
   249                            
   250                           )
   251                         )
   252                        )
   253                      
   254                     )
   255                     handles: (Any 0.607375 1.0)
   256                   )
   257                  (ArbitraryComponentSpec
   258                     name: 'helpTextView'
   259                     hasHorizontalScrollBar: true
   260                     hasVerticalScrollBar: true
   261                     miniScrollerHorizontal: true
   262                     miniScrollerVertical: true
   263                     hasBorder: false
   264                     component: helpTextView
   265                   )
   266                  )
   267                
   268               )
   269               handles: (Any 0.679181 1.0)
   270             )
   271            )
   272          
   273         )
   274       )
   275 !
   276 
   277 windowSpec
   278     "This resource specification was automatically generated
   279      by the UIPainter of ST/X."
   280 
   281     "Do not manually edit this!! If it is corrupted,
   282      the UIPainter may not be able to read the specification."
   283 
   284     "
   285      UIPainter new openOnClass:UIHelpTool andSelector:#windowSpec
   286      UIHelpTool new openInterface:#windowSpec
   287      UIHelpTool open
   288     "
   289 
   290     <resource: #canvas>
   291 
   292     ^ 
   293     #(FullSpec
   294        name: windowSpec
   295        window: 
   296       (WindowSpec
   297          label: 'Help Tool'
   298          name: 'Help Tool'
   299          min: (Point 300 300)
   300          bounds: (Rectangle 0 0 498 429)
   301          menu: menu
   302        )
   303        component: 
   304       (SpecCollection
   305          collection: (
   306           (ViewSpec
   307              name: 'mainPanel'
   308              layout: (LayoutFrame 0 0.0 0 0.0 0 1.0 -24 1.0)
   309              component: 
   310             (SpecCollection
   311                collection: (
   312                 (UISubSpecification
   313                    name: 'innerSpec'
   314                    layout: (LayoutFrame 0 0.0 0 0.0 0 1.0 -24 1.0)
   315                    minorKey: innerSpec
   316                  )
   317                 (UISubSpecification
   318                    name: 'windowSpecForCommit'
   319                    layout: (LayoutFrame 0 0.0 -30 1.0 0 1.0 0 1.0)
   320                    majorKey: ToolApplicationModel
   321                    minorKey: windowSpecForCommit
   322                  )
   323                 )
   324               
   325              )
   326            )
   327           (UISubSpecification
   328              name: 'infoBarSubSpec'
   329              layout: (LayoutFrame 0 0 -24 1 0 1 0 1)
   330              majorKey: ToolApplicationModel
   331              minorKey: windowSpecForInfoBar
   332            )
   333           )
   334         
   335        )
   336      )
   337 ! !
   338 
   339 !UIHelpTool class methodsFor:'menu specs'!
   340 
   341 helpTextMenu
   342     "This resource specification was automatically generated
   343      by the MenuEditor of ST/X."
   344 
   345     "Do not manually edit this!! If it is corrupted,
   346      the MenuEditor may not be able to read the specification."
   347 
   348     "
   349      MenuEditor new openOnClass:UIHelpTool andSelector:#helpTextMenu
   350      (Menu new fromLiteralArrayEncoding:(UIHelpTool helpTextMenu)) startUp
   351     "
   352 
   353     <resource: #menu>
   354 
   355     ^ 
   356      #(#Menu
   357 	#(
   358 	 #(#MenuItem
   359 	    #activeHelpKey: #commitOK
   360 	    #enabled: #contentsModifiedChannel
   361 	    #label: 'Accept'
   362 	    #itemValue: #accept
   363 	    #translateLabel: true
   364 	  )
   365 	 #(#MenuItem
   366 	    #activeHelpKey: #commitCancel
   367 	    #enabled: #contentsModifiedChannel
   368 	    #label: 'Cancel'
   369 	    #itemValue: #cancel
   370 	    #translateLabel: true
   371 	  )
   372 	 )
   373 	nil
   374 	nil
   375       )
   376 !
   377 
   378 keyItemMenu
   379     "This resource specification was automatically generated
   380      by the MenuEditor of ST/X."
   381 
   382     "Do not manually edit this!! If it is corrupted,
   383      the MenuEditor may not be able to read the specification."
   384 
   385     "
   386      MenuEditor new openOnClass:UIHelpTool andSelector:#keyItemMenu
   387      (Menu new fromLiteralArrayEncoding:(UIHelpTool keyItemMenu)) startUp
   388     "
   389 
   390     <resource: #menu>
   391 
   392     ^ 
   393      #(#Menu
   394 	#(
   395 	 #(#MenuItem
   396 	    #activeHelpKey: #deleteHelpTextKey
   397 	    #label: 'Delete'
   398 	    #itemValue: #doDelete
   399 	    #translateLabel: true
   400 	  )
   401 	 )
   402 	nil
   403 	nil
   404       )
   405 !
   406 
   407 listOfKeysMenu
   408     "This resource specification was automatically generated
   409      by the MenuEditor of ST/X."
   410 
   411     "Do not manually edit this!! If it is corrupted,
   412      the MenuEditor may not be able to read the specification."
   413 
   414     "
   415      MenuEditor new openOnClass:UIHelpTool andSelector:#listOfKeysMenu
   416      (Menu new fromLiteralArrayEncoding:(UIHelpTool listOfKeysMenu)) startUp
   417     "
   418 
   419     <resource: #menu>
   420 
   421     ^ 
   422      #(#Menu
   423 	#(
   424 	 #(#MenuItem
   425 	    #activeHelpKey: #deleteHelpTextKey
   426 	    #label: 'Delete'
   427 	    #itemValue: #doDelete
   428 	    #translateLabel: true
   429 	  )
   430 	 )
   431 	nil
   432 	nil
   433       )
   434 !
   435 
   436 menu
   437     "This resource specification was automatically generated
   438      by the MenuEditor of ST/X."
   439 
   440     "Do not manually edit this!! If it is corrupted,
   441      the MenuEditor may not be able to read the specification."
   442 
   443     "
   444      MenuEditor new openOnClass:UIHelpTool andSelector:#menu
   445      (Menu new fromLiteralArrayEncoding:(UIHelpTool menu)) startUp
   446     "
   447 
   448     <resource: #menu>
   449 
   450     ^ 
   451      #(Menu
   452         (
   453          (MenuItem
   454             label: 'File'
   455             translateLabel: true
   456             submenu: 
   457            (Menu
   458               (
   459                (MenuItem
   460                   label: 'New'
   461                   itemValue: doNew
   462                   translateLabel: true
   463                 )
   464                (MenuItem
   465                   label: '-'
   466                 )
   467                (MenuItem
   468                   activeHelpKey: fileLoad
   469                   label: 'Load...'
   470                   itemValue: doLoad
   471                   translateLabel: true
   472                 )
   473                (MenuItem
   474                   activeHelpKey: fileSave
   475                   label: 'Save'
   476                   itemValue: doSave
   477                   translateLabel: true
   478                 )
   479                (MenuItem
   480                   label: '-'
   481                   isVisible: isStandAlone
   482                 )
   483                (MenuItem
   484                   activeHelpKey: fileExit
   485                   label: 'Exit'
   486                   itemValue: closeRequest
   487                   translateLabel: true
   488                   isVisible: isStandAlone
   489                 )
   490                )
   491               nil
   492               nil
   493             )
   494           )
   495          (MenuItem
   496             label: 'Edit'
   497             translateLabel: true
   498             submenuChannel: keyItemMenu
   499             keepLinkedMenu: true
   500           )
   501          (MenuItem
   502             label: 'History'
   503             translateLabel: true
   504             isVisible: isStandAlone
   505             submenuChannel: menuHistory
   506           )
   507          (MenuItem
   508             label: 'MENU_Help'
   509             translateLabel: true
   510             startGroup: conditionalRight
   511             submenuChannel: menuHelp
   512           )
   513          )
   514         nil
   515         nil
   516       )
   517 ! !
   518 
   519 !UIHelpTool methodsFor:'accessing'!
   520 
   521 alternativeSpecSelectors
   522     "returns a set of alternative spec method selectors of the resource spec"
   523 
   524     ^ #( flyByHelpSpec tooltipSpec )
   525 !
   526 
   527 helpKey
   528     "returns the helpKey (symbol) or nil
   529     "
   530     |key|
   531 
   532     key := editModel value.
   533 
   534     key size ~~ 0 ifTrue:[
   535         key := key withoutSeparators.
   536         key notEmpty ifTrue:[ ^ key asSymbol ]
   537     ].
   538     ^ nil
   539 !
   540 
   541 helpKey:aKey
   542     "change the helpKey without any change notification (modifiedHolder).
   543     "
   544     |key|
   545 
   546     self withoutModifyDo:[
   547         aKey size ~~ 0 ifTrue:[
   548             key := aKey withoutSeparators asNilIfEmpty.
   549         ] ifFalse:[
   550             key := nil
   551         ].
   552         editModel value:key.
   553     ].
   554     self cancel.
   555 !
   556 
   557 modified
   558     "true if any items are added, deleted or modified
   559     "
   560     classItemList do:[:aClassItem|
   561 	aClassItem modified ifTrue:[^ true].
   562     ].
   563     ^ false
   564 !
   565 
   566 modified:aBoolean
   567     "true if any items are added, deleted or modified
   568     "
   569     classItemList do:[:aClassItem| aClassItem modified:aBoolean ].
   570 !
   571 
   572 modifiedHolder
   573     "boolean holder which is set to true if the helpKey or contents changed
   574     "
   575     ^ modifiedHolder
   576 !
   577 
   578 modifiedHolder:aValueHolder
   579     "boolean holder which is set to true if the helpKey or contents changed
   580     "
   581     modifiedHolder notNil ifTrue:[
   582 	modifiedHolder removeDependent:self. 
   583     ].
   584     modifiedHolder := aValueHolder.
   585 
   586     modifiedHolder notNil ifTrue:[
   587 	modifiedHolder addDependent:self.
   588     ].
   589 !
   590 
   591 specClass
   592     "returns the class on which the help tool works on
   593     "
   594     ^ specClass
   595 !
   596 
   597 specSelector
   598     "returns the selector of the edited helpSpec method
   599     "
   600     ^ specSelector ? #helpSpec
   601 ! !
   602 
   603 !UIHelpTool methodsFor:'aspects'!
   604 
   605 classItemListHolder
   606     "returns the holder which keeps the class items
   607     "
   608     |holder|
   609 
   610     holder := builder bindingAt:#classItemListHolder.
   611 
   612     holder isNil ifTrue:[
   613 	holder := nil asValue.
   614 	holder value:classItemList.
   615 	builder aspectAt:#classItemListHolder put:holder.
   616     ].
   617     ^ holder
   618 !
   619 
   620 classItemModel
   621     "returns the holder which keeps the current selected class
   622     "
   623     ^ classItemModel
   624 !
   625 
   626 contentsModifiedChannel
   627     "boolean holder, which is set to true if the contents assigned to the
   628      helpKey changed
   629     "
   630     ^ contentsModifiedChannel
   631 !
   632 
   633 editModel
   634     "string holder, which keeps the current editing helpKey as string
   635     "
   636     ^ editModel.
   637 !
   638 
   639 enablingCommitButtonsHolder
   640     "returns the enabling of the commit of this tool as value holder"
   641 
   642     masterApplication notNil ifTrue:[
   643         ^ masterApplication enablingCommitButtonsHolder
   644     ].
   645     ^ contentsModifiedChannel
   646 !
   647 
   648 helpTextView
   649     "the editView which shows the current help contents assigned to the key
   650     "
   651     ^ helpTextView
   652 !
   653 
   654 infoLabelHolder
   655     "returns the info label as value holder"
   656 
   657     masterApplication notNil ifTrue:[
   658         builder aspectAt:#useAlienInfoLabelHolder put:true.
   659         ^ masterApplication infoLabelHolder
   660     ].
   661     ^ super infoLabelHolder
   662 !
   663 
   664 keyItemListHolder
   665     "holder, which keeps the current hierarchical list
   666      assigned to the selected class item
   667     "
   668     |holder|
   669 
   670     holder := builder bindingAt:#keyItemListHolder.
   671 
   672     holder isNil ifTrue:[
   673 	holder := nil asValue.
   674 	holder value:(classItemList last list).
   675 	builder aspectAt:#keyItemListHolder put:holder.
   676     ].
   677     ^ holder
   678 !
   679 
   680 keyItemModel
   681     "model which keeps the current selected helpKey or nil
   682     "
   683     ^ keyItemModel.
   684 ! !
   685 
   686 !UIHelpTool methodsFor:'building'!
   687 
   688 buildAndMergeFromClass:aClass
   689      "setup a new specClass, merge the current items into
   690      "
   691      |root mergeItems|
   692 
   693      root := classItemList first.
   694 
   695      root isUnspecified ifTrue:[ mergeItems := root children ]
   696                        ifFalse:[ mergeItems := nil ].
   697 
   698      self loadFromClass:aClass.
   699 
   700      mergeItems size ~~ 0 ifTrue:[
   701         root := classItemList first.
   702 
   703         mergeItems do:[:anItem| |item hkey|
   704             hkey := anItem helpKey.
   705             item := root detectItemWithKey:hkey.
   706 
   707             item isNil ifTrue:[
   708                 item := KeyItem helpKey:hkey helpText:(anItem helpText).
   709                 root add:item sortBlock:[:a :b| a label < b label ].
   710             ] ifFalse:[
   711                 item helpText:(anItem helpText).
   712             ]
   713         ]
   714     ].
   715 !
   716 
   717 loadFromClass:aClass
   718     "reads the help dictionary from aClass and find remaining classes 
   719      'between' aClass and ApplicationModel
   720     " 
   721     |lastContents root list helpSpecSelector alternativeSelector|
   722 
   723     (specClass notNil and:[specClass == aClass]) ifTrue:[
   724         ^ self.
   725     ].
   726 
   727     helpSpecSelector := self specSelector.
   728     specClass := self getHelpSpecClassFromClass:aClass.
   729 
   730     aClass notNil ifTrue:[
   731         (aClass theMetaclass implements:helpSpecSelector) ifFalse:[
   732             alternativeSelector := (self alternativeSpecSelectors ? #()) detect:[:sel | aClass theMetaclass implements:sel] ifNone:nil.
   733             alternativeSelector notNil ifTrue:[
   734                 helpSpecSelector := specSelector := alternativeSelector.
   735                 specClass := aClass.
   736             ].
   737         ].
   738     ].
   739     
   740     list := OrderedCollection new.
   741 
   742     (specClass isClass and:[specClass isLoaded]) ifTrue:[
   743         lastContents := nil.
   744 
   745         self addHistoryEntryForClass:specClass selector:helpSpecSelector.
   746 
   747         specClass withAllSuperclasses reverseDo:[:aClass| |value name|
   748             lastContents isNil ifTrue:[
   749                 aClass == ApplicationModel ifTrue:[ 
   750                     lastContents := IdentityDictionary new
   751                 ].
   752             ] ifFalse:[
   753                 root := ClassItem onClass:aClass.
   754 
   755                 (aClass respondsTo: helpSpecSelector) ifTrue:[ 
   756                     value := aClass perform: helpSpecSelector.
   757                 ].
   758 
   759                 value notNil ifTrue:[
   760                     (value isDictionary) ifTrue:[
   761                         value keysAndValuesDo:[:k :v| |cval|
   762                             cval := lastContents at:k ifAbsent:self.
   763                             cval = v ifFalse:[ root add:(KeyItem helpKey:k helpText:v) ].
   764                         ].
   765                         lastContents := value.
   766                     ] ifFalse:[
   767                         |dict|
   768                         dict := Dictionary new.
   769                         value pairWiseDo:[:k :v| |cval|
   770                             cval := lastContents at:k ifAbsent:self.
   771                             cval = v ifFalse:[ root add:(KeyItem helpKey:k helpText:v) ].
   772                             dict at:k put:v.
   773                         ].
   774                         lastContents := dict.
   775                     ].
   776                 ].
   777                 root sort:[:a :b| a label < b label ].
   778                 root modified:false.
   779                 list add:root.
   780             ]
   781         ]
   782     ].
   783     list isEmpty ifTrue:[
   784         list add:(ClassItem onClass:nil)
   785     ].
   786 
   787     self withoutModifyDo:[
   788         classItemList contents:list.
   789         self updateIcons.
   790         classItemModel value:(list last)
   791     ].
   792 !
   793 
   794 loadFromClass:aClass andSelector:aSelector
   795     "reads the help dictionary from aClass"
   796 
   797     self assert:(aClass isNil or:[aClass isClass]).
   798 
   799     specSelector := aSelector.
   800     self loadFromClass:aClass
   801 !
   802 
   803 loadFromHelpTool:aHelpTool
   804     "build from another helpTool
   805     "
   806     specClass     := aHelpTool specClass.
   807     specSelector  := aHelpTool specSelector.
   808     classItemList := aHelpTool classItemListHolder value.
   809 
   810     self classItemListHolder value:classItemList.
   811 
   812     classItemModel triggerValue:(classItemList last).
   813 ! !
   814 
   815 !UIHelpTool methodsFor:'change & update'!
   816 
   817 editModelChanged
   818     "called if the editModel changed
   819     "
   820     |key|
   821 
   822     key := self helpKey.
   823 
   824     modifiedHolder notNil ifTrue:[
   825         modifiedHolder value:true
   826     ].
   827 
   828     contentsModifiedChannel value:false.
   829 
   830     key notNil ifTrue:[
   831         keyItemModel value = key ifTrue:[^ self].
   832 
   833         classItemList reverseDo:[:root| |item|
   834             item := root detectItemWithKey:key.
   835 
   836             item notNil ifTrue:[
   837                 classItemModel value:root.
   838                 keyItemModel   value:item.
   839                 ^ self.
   840             ].
   841         ].
   842 
   843         masterApplication isNil ifTrue:[
   844             "entered a new helpKey
   845             "
   846             self enablingCommitButtonsHolder value:true.
   847         ].
   848     ].
   849     keyItemModel value:nil.
   850 !
   851 
   852 update:something with:aParameter from:changedObject
   853     "Invoked when an object that I depend upon sends a change notification.
   854     "
   855     |root item list|
   856 
   857     changedObject == keyItemModel ifTrue:[
   858 	item := keyItemModel value.
   859 
   860 	item notNil ifTrue:[
   861 	    editModel value:(item helpKey).
   862 	].
   863 	self cancel.
   864 	^ self
   865     ].
   866 
   867     changedObject == classItemModel ifTrue:[
   868 	root := classItemModel value.
   869 
   870 	root notNil ifTrue:[
   871 	    item := root detectItemWithKey:(self helpKey).
   872 	    list := root list.
   873 	] ifFalse:[
   874 	    list := item := nil.
   875 	].
   876 
   877 	item notNil ifTrue:[
   878 	    keyItemModel value:nil withoutNotifying:self.
   879 	].
   880 	self keyItemListHolder value:list.
   881 	keyItemModel value:item.
   882 	^ self
   883     ].
   884 
   885     changedObject == editModel ifTrue:[
   886 	self editModelChanged.
   887 	^ self
   888     ].
   889 
   890     changedObject == contentsModifiedChannel ifTrue:[
   891 	modifiedHolder notNil ifTrue:[
   892 	    modifiedHolder value:true
   893 	].
   894 	^ self
   895     ].
   896     super update:something with:aParameter from:changedObject
   897 !
   898 
   899 withoutModifyDo:aBlock
   900     "discard modifications; trigger not the modifiedHolder during
   901      the action is active"
   902 
   903     |holder|
   904 
   905     modifiedHolder isNil ifTrue:[
   906         ^ aBlock value
   907     ].
   908     holder := modifiedHolder.
   909     ^ aBlock ensure:[modifiedHolder := holder]
   910 ! !
   911 
   912 !UIHelpTool methodsFor:'private'!
   913 
   914 getHelpSpecClassFromClass:aClass
   915     |cls|
   916 
   917     aClass isNil ifTrue:[^ nil].
   918 
   919     cls := self resolveName:aClass.
   920     cls isNil ifTrue:[ ^ nil ].
   921 
   922     cls := cls perform:#helpSpecClass ifNotUnderstood:cls.
   923 
   924     (cls isBehavior and:[cls isLoaded]) ifTrue:[
   925         ^ cls
   926     ].
   927     ^ nil
   928 !
   929 
   930 loadFromMessage:classAndSelector
   931     "Set and rebuild the specClass and specSelector from a resource string.
   932      On success true is returned otherwise false. If the current spec is
   933      modified, a dialog is launched."
   934 
   935     self askForModification ifFalse:[ ^ false].
   936 
   937     classAndSelector notNil ifTrue:[
   938         self loadFromClass:(classAndSelector methodClass) andSelector:(classAndSelector methodSelector).
   939         ^ true
   940     ].
   941     ^ false
   942 !
   943 
   944 updateIcons
   945     "update all icons (redefinitions below above or both)
   946     "
   947     |iconBelow iconAbove iconAboveAndBelow isBehind redefinedAbove redefinedBelow icon|
   948 
   949     "/ if only one class exists, its not possible to have redefinitions
   950     classItemList size > 1 ifFalse:[ ^ self ].
   951 
   952     iconBelow         := SystemBrowser medium_methodRedefinedBelowIcon.
   953     iconAbove         := SystemBrowser medium_methodInheritedFromAboveIcon.
   954     iconAboveAndBelow := SystemBrowser medium_methodInheritedFromAboveAndRedefinedBelowIcon.
   955 
   956     classItemList do:[:runClass|
   957         runClass do:[:aKeyItem|
   958             isBehind := redefinedBelow := redefinedAbove := false.
   959 
   960             classItemList do:[:testClass|
   961                 testClass == runClass ifTrue:[
   962                     isBehind := true
   963                 ] ifFalse:[
   964                     (testClass detectItemWithKey:(aKeyItem helpKey)) notNil ifTrue:[
   965                         isBehind ifTrue:[ redefinedBelow := true ]
   966                                 ifFalse:[ redefinedAbove := true ].
   967                     ]
   968                 ]
   969             ].
   970 
   971             redefinedBelow ifTrue:[
   972                 redefinedAbove ifTrue:[ icon := iconAboveAndBelow ]
   973                               ifFalse:[ icon := iconBelow ]
   974             ] ifFalse:[
   975                 redefinedAbove ifTrue:[ icon := iconAbove ]
   976                               ifFalse:[ icon := nil ]
   977             ].
   978             aKeyItem icon:icon.
   979         ]
   980     ].
   981 ! !
   982 
   983 !UIHelpTool methodsFor:'startup & release'!
   984 
   985 closeRequest
   986     "asks for permission before closing"
   987 
   988     masterApplication isNil ifTrue:[
   989         super closeRequest.
   990     ].
   991 !
   992 
   993 commonPostBuild
   994     "/ using masters infoHolder ?
   995     (builder aspectAt:#useAlienInfoLabelHolder) == true ifTrue:[
   996         (builder componentAt:#mainPanel) layout bottomOffset:0.
   997         (builder componentAt:#infoBarSubSpec) beInvisible
   998     ]
   999 !
  1000 
  1001 initialize
  1002     "setup default attributes
  1003     "
  1004     super initialize.
  1005     self createBuilder.
  1006 
  1007     specSelector   := #helpSpec.
  1008 
  1009     classItemList  := List new.
  1010 
  1011     classItemModel := nil asValue.
  1012     classItemModel addDependent:self.
  1013 
  1014     keyItemModel := nil asValue.
  1015     keyItemModel addDependent:self.
  1016 
  1017     contentsModifiedChannel := false asValue.
  1018     contentsModifiedChannel addDependent:self.
  1019 
  1020     helpTextView := EditTextView new.
  1021     helpTextView acceptAction:[:dummy| self accept ].
  1022     helpTextView modifiedChannel:contentsModifiedChannel.
  1023 
  1024     editModel := nil asValue.
  1025     editModel addDependent:self.
  1026 
  1027     self loadFromClass:nil.
  1028 !
  1029 
  1030 openOnClass:aClass
  1031     "opens the UIHelpTool on aClass
  1032     "
  1033     self openOnClass:aClass andSelector:nil
  1034 !
  1035 
  1036 openOnClass:aClass andSelector: aSelector
  1037     "opens the UIHelpTool on aClass and aSelector"
  1038 
  1039     self openInterface:#windowSpec "ForStandAlone".
  1040 
  1041     builder window label:'Help Tool'.
  1042     self loadFromClass:aClass andSelector:aSelector
  1043 ! !
  1044 
  1045 !UIHelpTool methodsFor:'user actions'!
  1046 
  1047 accept
  1048     "accepts the help text
  1049     "
  1050     |helpKey helpItem root|
  1051 
  1052     helpKey := self helpKey.
  1053     helpKey isNil ifTrue:[^ self].
  1054 
  1055     root := classItemModel value.
  1056     root isNil ifTrue:[^ self].
  1057 
  1058     helpItem := root detectItemWithKey:helpKey.
  1059 
  1060     helpItem isNil ifTrue:[
  1061         helpItem := KeyItem helpKey:helpKey helpText:(helpTextView contents).
  1062         root add:helpItem sortBlock:[:a :b| a label < b label ].
  1063         self updateIcons.
  1064     ] ifFalse:[
  1065         helpItem helpText:(helpTextView contents).
  1066     ].
  1067 
  1068     contentsModifiedChannel value:false.
  1069     keyItemModel triggerValue:helpItem.
  1070 !
  1071 
  1072 cancel
  1073     "cancel modifications, reload helpText"
  1074 
  1075     |item contents modified|
  1076 
  1077     item := keyItemModel value.
  1078     modified := false.
  1079 
  1080     item notNil ifTrue:[
  1081         contents := item helpText.
  1082     ] ifFalse:[
  1083         contents := nil.
  1084 
  1085         modifiedHolder isNil ifTrue:[
  1086             modified := self helpKey notNil
  1087         ]
  1088     ].
  1089     helpTextView contents:contents.
  1090     contentsModifiedChannel value:modified.
  1091 
  1092     "Modified: / 29-08-2006 / 10:20:37 / cg"
  1093 !
  1094 
  1095 doDelete
  1096     "deletes the selected help key
  1097     "
  1098     |item|
  1099 
  1100     item := keyItemModel value.
  1101 
  1102     item notNil ifTrue:[
  1103         item remove.
  1104         item icon notNil ifTrue:[ self updateIcons ].
  1105     ].    
  1106     editModel value:nil.
  1107 !
  1108 
  1109 doLoad
  1110     "opens a Resource Selection Browser in order to get a resource message"
  1111 
  1112     self loadFromMessage: 
  1113         (ResourceSelectionBrowser
  1114             request: 'Load Help Spec From Class'
  1115             onSuperclass: nil
  1116             andClass: specClass
  1117             andSelector: (self specSelector)
  1118             withResourceTypes: (Array with: #help)).
  1119 
  1120     self updateInfoLabel
  1121 !
  1122 
  1123 doNew
  1124     "reset all to empty
  1125     "
  1126     contentsModifiedChannel value:false.
  1127     self helpKey:nil.
  1128     self loadFromClass:nil.
  1129 !
  1130 
  1131 doSave
  1132     "save the help spec to the spec-class(es)"
  1133 
  1134     specClass isNil ifTrue:[
  1135         self information:'No class specified !!'.
  1136         ^ nil
  1137     ].
  1138 "/ cg: the following test is rubbish !!
  1139 "/    (specClass isSubclassOf:ApplicationModel) ifFalse:[
  1140 "/        self information:(resources string:'Cannot save help into non-Application class').
  1141 "/        ^ nil
  1142 "/    ].
  1143 
  1144     classItemList do:[:aClassItem|
  1145         aClassItem theClass isNil ifTrue:[
  1146             aClassItem onClass:specClass
  1147         ].
  1148         aClassItem createHelpMethodNamed:(self specSelector) 
  1149     ].
  1150 !
  1151 
  1152 openDocumentation
  1153     "opens the documentation file of the Help Tool
  1154     "
  1155     self openHTMLDocument: 'tools/uipainter/HelpTool.html'
  1156 ! !
  1157 
  1158 !UIHelpTool::ClassItem class methodsFor:'instance creation'!
  1159 
  1160 onClass:aClass
  1161     |root|
  1162 
  1163     root := self new.
  1164     root onClass:aClass.
  1165     ^ root
  1166 ! !
  1167 
  1168 !UIHelpTool::ClassItem methodsFor:'accessing'!
  1169 
  1170 list
  1171     "returns the hierarchical list assigned to the classItem; the
  1172      list contains the keyItems
  1173     "
  1174     list isNil ifTrue:[
  1175 	list := HierarchicalList new.
  1176 	list showRoot:false.
  1177 	list root:self.
  1178     ].
  1179     ^ list
  1180 !
  1181 
  1182 theClass
  1183     "returns the class or nil if unspecified
  1184     "
  1185     ^ theClass
  1186 ! !
  1187 
  1188 !UIHelpTool::ClassItem methodsFor:'change & update'!
  1189 
  1190 helpTextChangedFor:anItem
  1191     "called if an helpKey changed its contents
  1192     "
  1193     self model notNil ifTrue:[
  1194 	self   modified:true.
  1195 	anItem modified:true.
  1196     ].
  1197 ! !
  1198 
  1199 !UIHelpTool::ClassItem methodsFor:'code generation'!
  1200 
  1201 createHelpMethodNamed:aMethodName
  1202     |stream|
  1203 
  1204     modified ifFalse:[
  1205         ^ self
  1206     ].
  1207     theClass isNil ifTrue:[
  1208         theClass := Dialog requestClass:'Save helpSpec in which class?' initialAnswer:''.
  1209         theClass isNil ifTrue:[
  1210             ^ self
  1211         ].
  1212     ].
  1213     stream := '' writeStream.
  1214 
  1215     stream nextPutAll:
  1216         aMethodName, '\' withCRs,
  1217         (ResourceSpecEditor codeGenerationCommentForClass:UIHelpTool) withCRs,
  1218     '\\' withCRs,
  1219     '    "\' withCRs,
  1220     '     UIHelpTool openOnClass:', theClass name asString ,'
  1221     "
  1222 
  1223     <resource: #help>
  1224 
  1225     ^ super ', aMethodName, ' addPairsFrom:#(
  1226 
  1227 '.
  1228 
  1229     self do:[:aKeyItem| |helpText|
  1230         helpText := aKeyItem helpText.
  1231         helpText isNil ifTrue:[ helpText := '' ].
  1232 
  1233         stream nextPutLine:(aKeyItem helpKey storeString).
  1234         stream nextPutLine:(helpText storeString); cr.
  1235     ].
  1236     stream nextPutLine:')'.
  1237 
  1238     Compiler
  1239         compile:(stream contents)
  1240         forClass:theClass class
  1241         inCategory:'help specs'.
  1242 
  1243     self modified:false.
  1244 ! !
  1245 
  1246 !UIHelpTool::ClassItem methodsFor:'displaying'!
  1247 
  1248 icon
  1249     "returns the display icon (always nil)
  1250     "
  1251     ^ nil
  1252 !
  1253 
  1254 label
  1255     "returns the display label
  1256     "
  1257     |label|
  1258 
  1259     theClass notNil ifTrue:[ label := theClass name ]
  1260 		   ifFalse:[ label := '** not yet defined **' ].
  1261 
  1262     modified ifTrue:[
  1263 	label := Text string:label color:(Color red).
  1264     ].
  1265     ^ label
  1266 ! !
  1267 
  1268 !UIHelpTool::ClassItem methodsFor:'instance creation'!
  1269 
  1270 initialize
  1271     "setup defaults
  1272     "
  1273     super initialize.
  1274 
  1275     children   := OrderedCollection new.
  1276     isExpanded := true.
  1277     modified   := false.
  1278 !
  1279 
  1280 onClass:aClass
  1281     "the class the ys are assigned to; if the class is nil,
  1282      the class is not yet specified.
  1283     "
  1284     theClass := aClass.
  1285 ! !
  1286 
  1287 !UIHelpTool::ClassItem methodsFor:'private'!
  1288 
  1289 basicAdd:aChild sortBlock:aBlock
  1290     "catch low-level add to update the modification flag
  1291     "
  1292     self   modified:true.
  1293     aChild modified:true.
  1294 
  1295     ^ super basicAdd:aChild sortBlock:aBlock.
  1296 !
  1297 
  1298 basicAddAll:aList beforeIndex:anIndex
  1299     "catch low-level add to update the modification flag
  1300     "
  1301     self modified:true.
  1302 
  1303     aList do:[:el| el modified:true ].
  1304     ^ super basicAddAll:aList beforeIndex:anIndex.
  1305 !
  1306 
  1307 basicRemoveFromIndex:startIndex toIndex:stopIndex
  1308     "catch low-level remove to update the modification flag
  1309     "
  1310     self isUnspecified ifFalse:[
  1311 	self modified:true.
  1312     ].
  1313     ^ super basicRemoveFromIndex:startIndex toIndex:stopIndex
  1314 ! !
  1315 
  1316 !UIHelpTool::ClassItem methodsFor:'queries'!
  1317 
  1318 isUnspecified
  1319     "true if the class is unspecified
  1320     "
  1321     ^ theClass isNil
  1322 !
  1323 
  1324 modified
  1325     "true, if any item is modified, created or deleted
  1326     "
  1327     ^ modified
  1328 !
  1329 
  1330 modified:aBoolean
  1331     "true, if any item is modified, created or deleted
  1332     "
  1333     modified ~~ aBoolean ifTrue:[
  1334 	modified := aBoolean.
  1335 
  1336 	modified ifFalse:[
  1337 	    self do:[:el| el modified:false ].
  1338 	].
  1339     ].
  1340 ! !
  1341 
  1342 !UIHelpTool::ClassItem methodsFor:'searching'!
  1343 
  1344 detectItemWithKey:aKey
  1345     "returns the item assigned to a helpKey or nil
  1346     "
  1347     |key|
  1348 
  1349     aKey isEmptyOrNil ifTrue:[ ^ nil ].
  1350     key := aKey asSymbol.
  1351 
  1352     self do:[:anItem|
  1353         anItem helpKey == key ifTrue:[ ^ anItem ].
  1354     ].
  1355     ^ nil
  1356 ! !
  1357 
  1358 !UIHelpTool::KeyItem class methodsFor:'instance creation'!
  1359 
  1360 helpKey:aKey helpText:aText 
  1361     |key|
  1362 
  1363     key := self new.
  1364     key helpKey:aKey helpText:aText.
  1365     ^ key
  1366 ! !
  1367 
  1368 !UIHelpTool::KeyItem methodsFor:'accessing'!
  1369 
  1370 helpKey
  1371     "returns the helpKey, a symbol"
  1372 
  1373     ^ helpKey
  1374 !
  1375 
  1376 helpText
  1377     "returns the contents assigned to the helpKey or nil
  1378     "
  1379     ^ helpText
  1380 !
  1381 
  1382 helpText:aText
  1383     "set the contents assigned to the helpKey; if the contents changes,
  1384      a notification is raised.
  1385     "
  1386     |text|
  1387 
  1388     text := self formatText:aText.
  1389 
  1390     text ~= helpText ifTrue:[
  1391         helpText := text.
  1392 
  1393         (modified or:[parent isNil]) ifFalse:[
  1394             parent helpTextChangedFor:self.
  1395         ]
  1396     ].
  1397 ! !
  1398 
  1399 !UIHelpTool::KeyItem methodsFor:'displaying'!
  1400 
  1401 icon
  1402     "returns the display icon (always nil)
  1403     "
  1404     ^ icon
  1405 !
  1406 
  1407 icon:anIcon
  1408 
  1409     icon ~= anIcon ifTrue:[
  1410         icon := anIcon.
  1411         self changed:#icon.
  1412     ].
  1413 !
  1414 
  1415 label
  1416     "returns the display label
  1417     "
  1418     modified ifTrue:[
  1419 	^ Text string:helpKey color:(Color red)
  1420     ].
  1421     ^ helpKey
  1422 ! !
  1423 
  1424 !UIHelpTool::KeyItem methodsFor:'instance creation'!
  1425 
  1426 helpKey:aKey helpText:aText
  1427     "set the key and contents without a change notification
  1428     "
  1429     helpKey  := aKey asSymbol.
  1430     helpText := self formatText:aText.
  1431 !
  1432 
  1433 initialize
  1434     "setup defaults
  1435     "
  1436     super initialize.
  1437     children := #().
  1438     modified := false.
  1439 ! !
  1440 
  1441 !UIHelpTool::KeyItem methodsFor:'private'!
  1442 
  1443 formatText:aText
  1444     "format the text, replace carriage return by spaces and compress spaces
  1445     "
  1446     |text result|
  1447 
  1448     aText size ~~ 0 ifTrue:[
  1449 	text := aText asString asCollectionOfWords.
  1450 
  1451 	text notEmpty ifTrue:[
  1452 	    result := text first.
  1453 
  1454 	    text from:2 do:[:t| result := result, ' ', t ].
  1455 	    ^ result
  1456        ].
  1457     ].
  1458     ^ nil
  1459 ! !
  1460 
  1461 !UIHelpTool::KeyItem methodsFor:'queries'!
  1462 
  1463 modified
  1464     "returns true if the helpText is modified
  1465     "
  1466     ^ modified
  1467 !
  1468 
  1469 modified:aBoolean
  1470     "set the modification flag
  1471     "
  1472     aBoolean == modified ifFalse:[
  1473 	modified := aBoolean.
  1474 	self changed:#redraw.
  1475     ].
  1476 ! !
  1477 
  1478 !UIHelpTool class methodsFor:'documentation'!
  1479 
  1480 version
  1481     ^ '$Header$'
  1482 !
  1483 
  1484 version_CVS
  1485     ^ '$Header$'
  1486 ! !
  1487