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