refactoring_custom/SmallSense__CustomMenuBuilder.st
author Jan Vrany <jan.vrany@fit.cvut.cz>
Mon, 13 Nov 2017 22:26:12 -0300
changeset 1060 af3a048f9618
parent 833 297eb38e4eee
child 1072 a44c741ee5ef
permissions -rw-r--r--
Fixed xompletion of instance variables in inspector

"
A custom code generation and refactoring support for Smalltalk/X
Copyright (C) 2013-2015 Jakub Nesveda
Copyright (C) 2013-now  Jan Vrany

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
"
"{ Package: 'stx:goodies/smallsense/refactoring_custom' }"

"{ NameSpace: SmallSense }"

Object subclass:#CustomMenuBuilder
	instanceVariableNames:'perspective menu submenuLabel afterMenuItemLabelled
		generatorOrRefactoringFilter resources navigationState manager
		errorPrinter'
	classVariableNames:''
	poolDictionaries:''
	category:'Interface-Refactoring-Custom-UI'
!

!CustomMenuBuilder class methodsFor:'documentation'!

copyright
"
A custom code generation and refactoring support for Smalltalk/X
Copyright (C) 2013-2015 Jakub Nesveda
Copyright (C) 2013-now  Jan Vrany

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
"
!

documentation
"
    Injects menu item with submenu filled with generators or refactorings to the given menu.
    Basically helps to extend system browser (NewSystemBrowser) context menu (for example
    the menu which pop-ups after right-click on the class list).

    [author:]
        Jakub Nesveda <nesvejak@fit.cvut.cz>
"
! !

!CustomMenuBuilder class methodsFor:'instance creation'!

new
    "return an initialized instance"

    ^ self basicNew initialize.
! !

!CustomMenuBuilder class methodsFor:'building'!

buildMenuForContext:context filter: filter
    ^ self new buildMenuForContext:context filter: filter

    "Created: / 26-08-2014 / 10:12:03 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!CustomMenuBuilder methodsFor:'accessing'!

afterMenuItemLabelled
    "Returns menu item label after which will be placed 
     new menu item with generators or refactorings"
    
    ^ afterMenuItemLabelled

    "Modified (comment): / 28-12-2014 / 23:22:55 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
!

afterMenuItemLabelled:aLabel 
    "see afterMenuItemLabeled"
    
    afterMenuItemLabelled := aLabel

    "Modified (comment): / 28-12-2014 / 23:20:31 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
!

errorPrinter
    "Returns printer (like Transcript) which should print/show errors while menu building.
    Better to print errors silently than destroy IDE functionality with recurring errors."

    ^ errorPrinter

    "Modified (comment): / 01-02-2015 / 19:38:14 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
!

errorPrinter: aPrinter
    "see errorPrinter"

    errorPrinter := aPrinter.

    "Modified (comment): / 01-02-2015 / 19:38:59 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
!

generatorOrRefactoringFilter
    "Returns one argument block which is used to filter generators or refactorings"

    ^ generatorOrRefactoringFilter

    "Modified (comment): / 28-12-2014 / 23:23:59 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
!

generatorOrRefactoringFilter: aOneArgBlock
    "see generatorOrRefactoringFilter"

    generatorOrRefactoringFilter := aOneArgBlock

    "Modified (comment): / 28-12-2014 / 23:25:34 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
!

groupsSortBlock
    "Returns a block used to sort generator or refactoring groups"

    ^ [ :a :b | 
        a size = b size ifTrue: [ 
            | i | 

            i := 1.

            [ i < a size and: [ (a at:i) = (b at:i) ] ] whileTrue: [
                i := i + 1 
            ].

            (a at:i) < (b at:i)
        ] ifFalse: [
            a size < b size
        ]
    ]

    "Created: / 28-12-2014 / 20:56:43 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
!

manager
    "Returns generator or refactoring manager which is used to access them.
    See CustomManager for more details."

    ^ manager

    "Modified (comment): / 28-12-2014 / 23:26:48 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
!

manager: aManager
    "see manager"

    manager := aManager

    "Modified (comment): / 28-12-2014 / 23:27:10 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
!

menu
    "Returns menu (instance of class Menu) in which is created new
    menu item with submenu filled with generators or refactorings"

    ^ menu

    "Modified (comment): / 28-12-2014 / 23:28:28 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
!

menu: aMenu
    "see menu"

    menu := aMenu

    "Modified (comment): / 28-12-2014 / 23:28:51 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
!

navigationState
    "see Tools::NavigationState"

    ^ navigationState

    "Modified (comment): / 28-12-2014 / 23:29:30 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
!

navigationState: aNavigationState
    "see Tools::NavigationState"

    navigationState := aNavigationState

    "Created: / 28-12-2014 / 10:09:12 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
    "Modified (comment): / 28-12-2014 / 23:29:54 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
!

perspective
    "see CustomPerspective"

    ^ perspective

    "Modified (comment): / 28-12-2014 / 23:30:10 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
!

perspective: aCustomPerspective
    "see CustomPerspective"

    perspective := aCustomPerspective

    "Modified (comment): / 28-12-2014 / 23:30:32 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
!

resources
    "Used to translate menu labels (resources string:)"

    ^ resources

    "Modified (comment): / 28-12-2014 / 23:31:49 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
!

resources: someResources
    "see resources"

    resources := someResources

    "Modified (comment): / 28-12-2014 / 23:32:37 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
!

submenuLabel
    "Returns label of menu item which contains submenu with generators or refactorings"

    ^ submenuLabel

    "Modified (comment): / 28-12-2014 / 23:33:38 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
!

submenuLabel: aLabel
    "see submenuLabel"

    submenuLabel := aLabel

    "Modified (comment): / 28-12-2014 / 23:33:54 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
! !

!CustomMenuBuilder methodsFor:'building'!

buildMenu
    | item context submenuChannel |

    (menu isNil or: [ perspective isNil ]) ifTrue: [ 
        self error: 'Attributes named menu and perspective are required.'
    ].

    item := MenuItem label: (resources string: submenuLabel).
    context := SmallSense::CustomBrowserContext 
                    perspective: perspective
                    state: navigationState.

    submenuChannel := [ self buildMenuForContext: context filter: generatorOrRefactoringFilter ].
    "Do not show empty context menu"
    submenuChannel value hasItems ifTrue: [ 
        item submenuChannel: submenuChannel.
        self 
            placeMenuItem: item 
            afterMenuItemLabeled: afterMenuItemLabelled 
            forMenu: menu 
    ]

    "Created: / 27-12-2014 / 17:20:05 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
    "Modified: / 04-01-2015 / 15:57:03 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
    "Modified: / 11-05-2015 / 09:07:25 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

buildMenuForContext: context filter: filter 
    | submenu generatorsAndRefactorings groups groupsMap |

    submenu := Menu new.
    generatorsAndRefactorings := manager generatorsAndRefactoringsSelect: [ :generatorOrRefactoring |
        [ (generatorOrRefactoring availableInPerspective: context perspective)
            and: [ filter value: generatorOrRefactoring ]
            and: [ generatorOrRefactoring availableForProgrammingLanguagesInContext: context ]
            and: [ generatorOrRefactoring label notNil ]
        ] on: Error do: [ :error |
            errorPrinter showCR: 'An error occured when selecting code generators/refactorings.'.
            errorPrinter showCR: 'Class: ', generatorOrRefactoring name, ' Error: ', error asString.  
            false
        ].
    ].

    "/ Now, group them by group.
    groupsMap := Dictionary new.
    groups := OrderedCollection new.
    generatorsAndRefactorings do:[:each |
        | group |

        group := each group.
        (groupsMap includesKey: group) ifTrue:[ 
            (groupsMap at: group) add: each.
        ] ifFalse:[ 
            groupsMap at: group put: (OrderedCollection with: each).
            groups add: group.
        ].
    ].

    groups sort: self groupsSortBlock.

    groups do:[:name |  
        | items |

        items := groupsMap at: name.
        items sort:[ :a :b | a label < b label ].
        items do:[:each | 
            | item |

            item := MenuItem label: (resources string: each label)
                    itemValue:[ each executeInContextWithWaitCursor: context ].
            item enabled:[ each availableInContext: context ].
            submenu addItem:item.
        ].
    ] separatedBy:[ 
        submenu addSeparator.
    ].

    ^ submenu

    "Created: / 26-08-2014 / 10:13:02 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 01-02-2015 / 20:18:02 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
!

placeMenuItem: aMenuItem afterMenuItemLabeled: aLabel forMenu: aMenu
    "Places a menu item after another menu item identified by label
    within given menu."    
    | index |

    index := aMenu indexOfMenuItemForWhich:[:each | each label = aLabel ].
    index ~~ 0 ifTrue:[
        "Labeled item found"
        aMenu addItem: aMenuItem beforeIndex: index + 1.
    ] ifFalse:[
        aMenu addItem: aMenuItem.
    ].

    "Created: / 27-12-2014 / 18:45:06 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
! !

!CustomMenuBuilder methodsFor:'initialization'!

initialize
    "Invoked when a new instance is created."

    menu := Menu new.
    submenuLabel := 'Unknown menu label'.
    generatorOrRefactoringFilter := [ :generatorOrRefactoring | true ].
    resources := self class classResources.
    manager := SmallSense::CustomManager current.
    errorPrinter := Transcript

    "Modified: / 01-02-2015 / 19:31:57 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
    "Modified: / 11-05-2015 / 09:07:08 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!CustomMenuBuilder class methodsFor:'documentation'!

version_HG

    ^ '$Changeset: <not expanded> $'
! !