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