Tools_ProjectList.st
author Claus Gittinger <cg@exept.de>
Mon, 06 Mar 2006 19:48:49 +0100
changeset 6655 d2b8f5af780f
parent 6492 9c446e709216
child 6709 4324874ea734
permissions -rw-r--r--
*** empty log message ***

"
 COPYRIGHT (c) 2000 by eXept Software AG
	      All Rights Reserved

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

"{ Package: 'stx:libtool' }"

"{ NameSpace: Tools }"

BrowserList subclass:#ProjectList
	instanceVariableNames:'projectList'
	classVariableNames:'AdditionalEmptyProjects'
	poolDictionaries:''
	category:'Interface-Browsers-New'
!

!ProjectList class methodsFor:'documentation'!

copyright
"
 COPYRIGHT (c) 2000 by eXept Software AG
	      All Rights Reserved

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

!ProjectList class methodsFor:'interface specs'!

singleProjectWindowSpec
    "This resource specification was automatically generated
     by the UIPainter of ST/X."

    "Do not manually edit this!! If it is corrupted,
     the UIPainter may not be able to read the specification."

    "
     UIPainter new openOnClass:ClassCategoryList andSelector:#singleCategoryWindowSpec
     ClassCategoryList new openInterface:#singleCategoryWindowSpec
    "

    <resource: #canvas>

    ^ 
     #(#FullSpec
	#name: #singleProjectWindowSpec
	#window: 
       #(#WindowSpec
	  #label: 'ProjectList'
	  #name: 'ProjectList'
	  #min: #(#Point 0 0)
	  #max: #(#Point 1024 721)
	  #bounds: #(#Rectangle 218 175 518 475)
	)
	#component: 
       #(#SpecCollection
	  #collection: #(
	   #(#LabelSpec
	      #label: 'ProjectName'
	      #name: 'ProjectLabel'
	      #layout: #(#LayoutFrame 0 0.0 0 0 0 1.0 25 0)
	      #translateLabel: true
	      #labelChannel: #projectLabelHolder
	      #menu: #menuHolder
	    )
	   )

	)
      )
!

windowSpec
    "This resource specification was automatically generated
     by the UIPainter of ST/X."

    "Do not manually edit this!! If it is corrupted,
     the UIPainter may not be able to read the specification."

    "
     UIPainter new openOnClass:ProjectList andSelector:#windowSpec
     ProjectList new openInterface:#windowSpec
     ProjectList open
    "

    <resource: #canvas>

    ^ 
     #(#FullSpec
        #name: #windowSpec
        #window: 
       #(#WindowSpec
          #label: 'ProjectList'
          #name: 'ProjectList'
          #min: #(#Point 0 0)
          #max: #(#Point 1024 721)
          #bounds: #(#Rectangle 13 23 313 323)
        )
        #component: 
       #(#SpecCollection
          #collection: #(
           #(#SequenceViewSpec
              #name: 'List'
              #layout: #(#LayoutFrame 0 0.0 0 0.0 0 1.0 0 1.0)
              #tabable: true
              #model: #selectedProjects
              #menu: #menuHolder
              #hasHorizontalScrollBar: true
              #hasVerticalScrollBar: true
              #miniScrollerHorizontal: true
              #isMultiSelect: true
              #valueChangeSelector: #selectionChangedByClick
              #useIndex: false
              #sequenceList: #projectList
              #doubleClickChannel: #doubleClickChannel
              #properties: 
             #(#PropertyListDictionary
                #dragArgument: nil
                #dropArgument: nil
                #canDropSelector: #canDropContext:
                #dropSelector: #doDropContext:
              )
            )
           )

        )
      )

    "Created: / 17.2.2000 / 23:45:47 / cg"
    "Modified: / 17.2.2000 / 23:47:53 / cg"
! !

!ProjectList class methodsFor:'queries-plugin'!

aspectSelectors
    ^ #( 
	#(#doubleClickChannel #action )
	immediateUpdate 
	selectedProjects 
	menuHolder 
	outGeneratorHolder 
	inGeneratorHolder 
	selectionChangeCondition
	updateTrigger
	forceGeneratorTrigger
	hideUnloadedClasses
	organizerMode
	slaveMode
       )

    "Created: / 17.2.2000 / 23:46:18 / cg"
    "Modified: / 25.2.2000 / 22:32:10 / cg"
! !

!ProjectList methodsFor:'aspects'!

projectLabelHolder
    ^ self pseudoListLabelHolder
!

projectList
    projectList isNil ifTrue:[
	projectList := ValueHolder new.
	projectList addDependent:self.
    ].
    ^ projectList

    "Created: / 17.2.2000 / 23:39:32 / cg"
!

selectedProjects
    ^ self selectionHolder

    "Created: / 17.2.2000 / 23:39:57 / cg"
!

selectedProjects:aValueHolder
    ^ self selectionHolder:aValueHolder
! !

!ProjectList methodsFor:'change & update'!

delayedUpdate:something with:aParameter from:changedObject
    |cls sel pkg mthd|

    self inSlaveModeOrInvisible 
    "/ (self slaveMode value == true) 
    ifTrue:[
	changedObject == Smalltalk ifTrue:[ listValid := false].
	something == #projectOrganization ifTrue:[ listValid := false].
	^ self
    ].

    changedObject == slaveMode ifTrue:[
	listValid ~~ true ifTrue:[
	    self enqueueDelayedUpdateList
	].
	"/ self invalidateList.
	^  self
    ].


    changedObject == Smalltalk ifTrue:[
	something == #projectOrganization ifTrue:[
	    self invalidateList.
	    self enqueueDelayedUpdateOutputGenerator.
	    ^ self.
	].
	something == #methodInClass ifTrue:[
	    listValid == true ifTrue:[
		cls := aParameter at:1.
		sel := aParameter at:2.
		mthd := cls compiledMethodAt:sel.
		mthd notNil ifTrue:[
		    pkg := mthd package.
		    (projectList value includes:pkg) ifFalse:[
			self invalidateList.
		    ]
		].
	    ].
	    ^ self
	].

	(something == #classDefinition
	or:[something == #newClass]) ifTrue:[
	    listValid == true ifTrue:[
		cls := aParameter.
		pkg := cls package.
		(projectList value includes:pkg) ifFalse:[
		    self invalidateList.
		] ifTrue:[
		    self enqueueDelayedUpdateOutputGenerator
		].
	    ] ifFalse:[
		self invalidateList
	    ].
	    ^ self
	].
	(something == #classRemove) ifTrue:[
	    listValid == true ifTrue:[
		cls := aParameter.
		pkg := cls package.
	    ].
	].
	^ self
    ].

"/    something == #projectOrganization ifTrue:[
"/        aParameter isSymbol ifTrue:[
"/                    "/ a single method has changed
"/"/                    sel := aParameter.
"/"/                    mthd := changedObject compiledMethodAt:sel.
"/            self enqueueDelayedUpdateOutputGenerator.
"/        ].
"/        ^ self
"/    ].

    (organizerMode notNil
    and:[organizerMode value ~~ #project]) ifTrue:[
	self invalidateList.
	^ self
    ].
    super delayedUpdate:something with:aParameter from:changedObject

    "Created: / 17.2.2000 / 23:41:02 / cg"
    "Modified: / 26.2.2000 / 01:21:49 / cg"
!

selectionChangedByClick
    "we are not interested in that - get another notification
     via the changed valueHolder"

    "Created: / 17.2.2000 / 23:41:17 / cg"
!

update:something with:aParameter from:changedObject
    changedObject == Smalltalk ifTrue:[
	something == #methodDictionary ifTrue:[
	    ^ self 
	].
	something == #methodTrap ifTrue:[
	    ^ self
	].
	something == #methodInClass ifTrue:[
	    ^ self
	].
	something == #classVariables ifTrue:[
	    ^ self
	].
	something == #classComment ifTrue:[
	    ^ self.
	].
	something == #methodInClassRemoved ifTrue:[
	    ^ self.
	].
    ].
    super update:something with:aParameter from:changedObject
! !

!ProjectList methodsFor:'drag & drop'!

canDropContext:aDropContext
    |methodsOrClasses package|

    methodsOrClasses := aDropContext dropObjects collect:[:obj | obj theObject].

    (methodsOrClasses contains:[:aMethodOrClass | (aMethodOrClass isMethod or:[aMethodOrClass isClass]) not]) ifTrue:[^ false].

    package := self packageAtTargetPointOf:aDropContext.
    package isNil ifTrue:[^ false].

    (methodsOrClasses contains:[:aMethodOrClass | aMethodOrClass package ~= package]) ifFalse:[^ false].
    ^ true
!

doDropContext:aDropContext
    |package methodsOrClasses methods classes|

    methodsOrClasses := aDropContext dropObjects collect:[:aDropObject | aDropObject theObject].
    (methodsOrClasses contains:[:something | (something isMethod or:[something isClass]) not]) ifTrue:[^ self].
    methods := methodsOrClasses select:[:something | something isMethod].
    classes := methodsOrClasses select:[:something | something isClass].

    package := self packageAtTargetPointOf:aDropContext.
    package notNil ifTrue:[
        methods notEmpty ifTrue:[
            self masterApplication moveMethods:methods toProject:package.
        ].
        classes notEmpty ifTrue:[
            self masterApplication moveClasses:classes toProject:package.
        ]
    ].
!

packageAtTargetPointOf:aDropContext
    |p packageListView lineNr item package dropInfo now 
     overItem timeOverItem|

    p := aDropContext targetPoint.

    packageListView := aDropContext targetWidget.

    dropInfo := aDropContext dropInfo.

    lineNr := packageListView yVisibleToLineNr:p y.
    lineNr isNil ifTrue:[^ nil].

    item := packageListView list value at:lineNr.
    item isNil ifTrue:[^ nil].

    item canExpand ifTrue:[
        now := Timestamp now.
        overItem := dropInfo at:#overItem ifAbsentPut:[item].
        timeOverItem := dropInfo at:#timeOverItem ifAbsentPut:[now].

        overItem ~~ item ifTrue:[
            dropInfo at:#timeOverItem put:now.
            dropInfo at:#overItem put:item.
            aDropContext passiveAction:[ self packageAtTargetPointOf:aDropContext ].
        ] ifFalse:[
            (now millisecondDeltaFrom:timeOverItem) >= (UserPreferences current timeToAutoExpandItemsWhenDraggingOver) ifTrue:[
                aDropContext saveDraw:[ item expand. packageListView repairDamage ].
                dropInfo removeKey:#timeOverItem.
                dropInfo removeKey:#overItem.
            ] ifFalse:[
                aDropContext passiveAction:[ self packageAtTargetPointOf:aDropContext ].
            ]
        ].
    ].

    package := item package.
    package = self class nameListEntryForALL ifTrue:[^ nil].
    ^ package.
! !

!ProjectList methodsFor:'generators'!

makeGenerator
    "return a generator which enumerates the classes from the selected project(s)."

    |selectedPackages thePackage hideUnloadedClasses|

    selectedPackages := self selectedProjects value.
    selectedPackages size == 0 ifTrue:[
	^ #()
    ].

    hideUnloadedClasses := self hideUnloadedClasses value.

    (selectedPackages includes:(self class nameListEntryForALL)) ifTrue:[
	hideUnloadedClasses ifTrue:[
	    ^ Iterator on:[:whatToDo |
			       Smalltalk allClassesDo:[:cls |
				   cls isLoaded ifTrue:[
				       (cls isNameSpace not or:[cls == Smalltalk]) ifTrue:[
					   whatToDo value:cls
				       ]
				   ]
			       ]
			  ]
	].
	^ Iterator on:[:whatToDo |
			   Smalltalk allClassesDo:[:cls |
			       (cls isNameSpace not or:[cls == Smalltalk]) ifTrue:[
				   whatToDo value:cls
			       ]
			   ]
		      ]
    ].

    selectedPackages size == 1 ifTrue:[
	"/ faster common case
	thePackage := selectedPackages first.

	^ Iterator on:[:whatToDo | |doInclude|
			   Smalltalk allClassesDo:[:cls |
			       (hideUnloadedClasses not or:[cls isLoaded])
			       ifTrue:[
				   (cls isNameSpace not or:[cls == Smalltalk]) ifTrue:[
				       doInclude := (thePackage = cls package).
				       doInclude ifFalse:[
					    cls isJavaClass ifFalse:[
					       doInclude := (cls methodDictionary contains:[:mthd | thePackage = mthd package])
							    or:[ cls class methodDictionary contains:[:mthd | thePackage = mthd package]].
					    ]
				       ].
				       doInclude ifTrue:[
					   whatToDo value:cls
				       ]
				   ]
			       ]
			   ]
		      ]
    ].

    ^ Iterator on:[:whatToDo |  |doInclude|
		       Smalltalk allClassesDo:[:cls |
			   (hideUnloadedClasses not or:[cls isLoaded])
			   ifTrue:[
			       (cls isNameSpace not or:[cls == Smalltalk]) ifTrue:[
				   doInclude := (selectedPackages includes:cls package).
				   doInclude ifFalse:[
					cls isJavaClass ifFalse:[
					   doInclude := (cls methodDictionary contains:[:mthd | thePackage = mthd package])
							or:[ cls class methodDictionary contains:[:mthd | thePackage = mthd package]].
					]
				   ].
				   doInclude ifTrue:[
				       whatToDo value:cls
				   ]
			       ]
			   ]
		       ]
		  ]

    "Created: / 17.2.2000 / 23:49:37 / cg"
    "Modified: / 24.2.2000 / 22:53:46 / cg"
! !

!ProjectList methodsFor:'private'!

defaultSlaveModeValue
    |org|

    (org := self topApplication initialOrganizerMode) == #project ifTrue:[^ false].
    org isNil ifTrue:[^ false].
    ^ true
!

initialOrganizerMode
    ^ #project
!

listOfProjects
    |allProjects generator|

    allProjects := IdentitySet new.

    inGeneratorHolder isNil ifTrue:[
        (self hideUnloadedClasses value) ifTrue:[
            Smalltalk allClassesDo:[:eachClass |
                |cls pkg|

                eachClass isLoaded ifTrue:[
                    cls := eachClass theNonMetaclass.
                    cls isPrivate ifTrue:[
                        cls := cls topOwningClass
                    ].
                    pkg := cls package.
                    pkg withoutSeparators size > 0 ifTrue:[
                        allProjects add:pkg asSymbol.
                    ] ifFalse:[
                        "/ for now, nameSpaces are not in any package;
                        "/ this might change. Then, 0-sized packages are
                        "/ illegal, and the following should be enabled.
                        "/ self halt
                    ].
                    cls isJavaClass ifFalse:[
                        cls instAndClassSelectorsAndMethodsDo:[:sel :mthd |
                            allProjects add:mthd package asSymbol.
                        ].
                    ].
                ].
            ].
            allProjects := allProjects asOrderedCollection.
        ] ifFalse:[
            allProjects := Smalltalk allProjectIDs.
        ].

        "/ those are simulated - in ST/X, empty projects do not
        "/ really exist; however, during browsing, it makes sense.
        AdditionalEmptyProjects size > 0 ifTrue:[
            "/ remove those that are present ...
            AdditionalEmptyProjects := AdditionalEmptyProjects select:[:pkg | (allProjects includes:pkg) not].
            allProjects addAll:AdditionalEmptyProjects.
        ].
    ] ifFalse:[
        generator := inGeneratorHolder value.
        generator isNil ifTrue:[^ #() ].
        generator do:[:prj | allProjects add:prj].
        allProjects := allProjects asOrderedCollection.
    ].

    allProjects sort.
    allProjects size == 1 ifTrue:[
        "/ self projectLabelHolder value:(allProjects first , ' [Project]').
        self projectLabelHolder value:(LabelAndIcon icon:(self class packageIcon) string:allProjects first).
    ].
    allProjects size > 1 ifTrue:[
        allProjects addFirst:(self class nameListEntryForALL).
    ].
    ^ allProjects

    "Created: / 17.2.2000 / 23:43:05 / cg"
    "Modified: / 18.8.2000 / 20:26:04 / cg"
!

makeDependent
    Smalltalk addDependent:self

    "Created: / 17.2.2000 / 23:43:13 / cg"
!

makeIndependent
    Smalltalk removeDependent:self.
!

release
    super release.

    projectList removeDependent:self.
!

updateList
    |newList oldSelection newSelection selectedProjectsHolder|

    selectedProjectsHolder := self selectedProjects.
    oldSelection := selectedProjectsHolder value.
    newList := self listOfProjects.
    newList ~= projectList value ifTrue:[
"/        oldSelection size > 0 ifTrue:[
"/            selectedProjectsHolder removeDependent:self.
"/            selectedProjectsHolder value:#().
"/            selectedProjectsHolder addDependent:self.
"/        ].

	self projectList value:newList.

	oldSelection size > 0 ifTrue:[
	    newSelection := oldSelection select:[:prj | newList includes:prj].
	    selectedProjectsHolder value:newSelection.
	]
    ].
    listValid := true.

    "Modified: / 25.2.2000 / 23:10:01 / cg"
! !

!ProjectList methodsFor:'special'!

addAdditionalProject:aProject
    "/ those are simulated - in ST/X, empty categories do not
    "/ really exist; however, during browsing, it makes sense.
    AdditionalEmptyProjects isNil ifTrue:[
	AdditionalEmptyProjects := Set new.
    ].
    AdditionalEmptyProjects add:aProject.

    Smalltalk changed:#projectOrganization   "/ not really ... to force update

    "Created: / 17.2.2000 / 23:44:27 / cg"
!

removeAdditionalProjects:aListOfProjects
    "/ those are simulated - in ST/X, empty categories do not
    "/ really exist; however, during browsing, it makes sense.
    AdditionalEmptyProjects notNil ifTrue:[
	aListOfProjects do:[:eachProject |
	    AdditionalEmptyProjects remove:eachProject ifAbsent:nil.
	].
    ].
    Smalltalk changed:#projectOrganization   "/ not really ... to force update

    "Created: / 17.2.2000 / 23:45:24 / cg"
! !

!ProjectList class methodsFor:'documentation'!

version
    ^ '$Header: /cvs/stx/stx/libtool/Tools_ProjectList.st,v 1.6 2006-03-06 18:48:49 cg Exp $'
! !