" DCI program: BB4bPlan "

" Exported from Squeak 7179-basic.76.image on: 18 December 2011 by: Trygve "

" Data perspective "

" Class BB4bActivity "

" Instances of this class represent the notion of an activity in a planning activity network.
Note that the successor and predecessor relations are not part of the activity; they are generated in a Context when needed.

See Controller>BB4aController for more information.

Instance variables:
    earlyStart (Integer) earliest start week for this activity.
    duration (Integer) in weeks
    name (String) activity name
    color (Color) simple representation of activity kind. "

Object subclass: #BB4bActivity
    instanceVariableNames: 'earlyStart duration name color'
    classVariableNames: ''
    poolDictionaries: ''
    category: 'BB4bPlan-Data'

" BB4bActivity instance methods in category: access "

color
    ^color

displayName
    ^name , ' (' , duration printString , ')'

duration
    ^duration

earlyFinish
    ^earlyStart
        ifNil: [nil]
        ifNotNil: [earlyStart + duration - 1]

earlyStart
    ^earlyStart

earlyStart: week
    earlyStart := week.

name
    ^name

resetForFrontload
    earlyStart := nil.

" BB4bActivity instance methods in category: private "

initialize
    earlyStart := nil.
    duration := 0.
    name := 'Act' , self asOop printString.
    color := Color gray.

name: nam duration: dur color: col
    name := nam.
    duration := dur.
    color := col.

printOn: strm
    super printOn: strm.
    strm nextPutAll: ' (' , name , ')'.

" BB4bActivity class class methods in category: instance creation "

name: nam duration: dur color: col
    | act |
    act := self new.
    act name: nam duration: dur color: col.
    ^act

" Class BB4bDependency "

" Instances of this class represents a predecessor/successor relationship between activities.

See Controller>BB4aController for more information.

Instance variables:
    predecessor (Activity)
    successor (Activity) "

Object subclass: #BB4bDependency
    instanceVariableNames: 'predecessor successor'
    classVariableNames: ''
    poolDictionaries: ''
    category: 'BB4bPlan-Data'

" BB4bDependency instance methods in category: access "

predecessor
    ^predecessor

successor
    ^successor

" BB4bDependency instance methods in category: private "

predecessor: pred successor: succ
    predecessor := pred.
    successor := succ.

printOn: strm
    super printOn: strm.
    strm nextPutAll: ' (' , predecessor name , '-->' , successor name , ')'.

" Class BB4bModel "

" The Model part of MVC. Represents an activity network.

See Controller>BB4bController for more information.

Instance variables:
    activities (Set of Activity)
    dependencies (Set of Dependency)
    
Note: There is no activityRanks instance variable here. It is in BB4bDependencyCtx, keeping the Model itself clean from system behavior details. "

Object subclass: #BB4bModel
    instanceVariableNames: 'activities dependencies'
    classVariableNames: ''
    poolDictionaries: ''
    category: 'BB4bPlan-Data'

" BB4bModel instance methods in category: access "

activityNamed: actNam
    | act |
    act := activities detect: [:a | a name = actNam] ifNone: [nil].
    act ifNil: [self error: 'Activity ' , actNam , ' does not exist.'. ^nil].
    ^act

allActivities
    ^activities

allDependencies
    ^dependencies

hasDependencyFrom: fromAct to: toAct
    | found |
    found := dependencies
        detect: [:dep | (dep predecessor = fromAct) and: [dep successor = toAct]]
        ifNone: [nil].
    ^found notNil

hasDependencyFromName: fromActName toName: toActName
    ^self
        hasDependencyFrom: (self activityNamed: fromActName)
        to: (self activityNamed: toActName)

predecessorsOf: succ
    | preds |
    preds := Set new.
    dependencies do: [:dep | dep successor == succ ifTrue: [preds add: dep predecessor]].
    ^preds

successorsOf: pred
    | succs |
    succs := Set new.
    dependencies do: [:dep | dep predecessor == pred ifTrue: [succs add: dep successor]].
    ^succs

" BB4bModel instance methods in category: data definition "

newActivityNamed: nam duration: dur color: col
    | act |
    act := BB4bActivity name: nam duration: dur color: col.
    activities add: act.
    self changed: #model.
    ^act

newDependencyFrom: predNam to: succNam
    | pred succ |
    pred := self activityNamed: predNam.
    succ := self activityNamed: succNam.
    (self hasDependencyFrom: pred to: succ)
    ifFalse:
        [dependencies add:
            (BB4bDependency new
                predecessor: pred
                successor: succ).
        self changed: #model].

reset
    activities := Set new.
    dependencies := Set new.
    self changed: #activities.
    self changed: #dependencies.

" BB4bModel instance methods in category: private "

initialize
    activities := Set new.
    dependencies := Set new.

" Context perspective "

" Context: BB4bDependencyCtx "

" Class BB4bDependencyCtx "

" This Context computes a number of values that support drawing the dependency diagram.
Let the cursor hover over the roles in the Interaction diagram to see how these values are computed.

The corresponding Interaction actually draws the diagram.
The presentation is simply based on rank where the rank of an activity is the max length of its predecessor chain.

Instance variables:
    view (DependencyView) The roles are computed for this view.
    rankedActivities (OrderedCollection rank -> activityCollection) The activities at each rank.
    activityRanks (Dictionary activity -> rank )

See Controller>BB4bController for more information. "

BB1Context subclass: #BB4bDependencyCtx
    instanceVariableNames: 'data view rankedActivities activityRanks'
    classVariableNames: ''
    poolDictionaries: ''
    category: 'BB4bPlan-Context'

" BB4bDependencyCtx instance methods in category: accessing "

data: aData
    data := aData.

" BB4bDependencyCtx instance methods in category: data manipulation "

remap
    self computeRankedActivities.
    super remap.

" BB4bDependencyCtx instance methods in category: initialization "

view: v
    view := v.

" BB4bDependencyCtx instance methods in category: private "

computeRankedActivities
    rankedActivities :=OrderedCollection new. " rank -> activityCollection "
    activityRanks := Dictionary new. " activity -> rank "
    data ifNil: [^nil].
    data allActivities do:
        [:act || rnk coll |
        rnk := self rankOf: act.
        activityRanks at: act put: rnk.
        coll := rankedActivities at: rnk ifAbsentPut: [SortedCollection sortBlock: [:x :y | x name < y name]].
        coll add: act].

initialize
    super initialize.
    rankedActivities := Dictionary new.
    activityRanks := nil.

rankOf: act
    " NOTE: A feature of the structure, not of an individual activity. "
    | rnk |
    ^activityRanks
        at: act
        ifAbsent:
            [rnk := 1.
            (data predecessorsOf: act) do: [:pred | rnk := rnk max: (self rankOf: pred) + 1].
        rnk]

" BB4bDependencyCtx instance methods in category: role binding "

Dependencies
    ^data allDependencies

MaxRank
    " rankedActivities :: OrderedCollection rank -> activityCollection "
    ^rankedActivities size

MaxRankSetSize
    " rankedActivities :: OrderedCollection rank -> activityCollection "
    | maxSize |
    maxSize := 0.
    rankedActivities do: [:coll | maxSize := maxSize max: coll size].
    ^maxSize

RankedActivityList
    " rankedActivities :: OrderedCollection rank -> activityCollection "
    ^rankedActivities

View
    ^view

" BB4bDependencyCtx instance methods in category: triggers "

data: aData refresh: aView
    data := aData.
    view := aView.
    self runInteractionFromRoleNamed: #View.

" BB4bDependencyCtx class class methods in category: context diagram "

linkBreakPoints
    | dict |
    (dict := Dictionary new)
        yourself.
    ^dict.

rolePositions
    | dict |
    (dict := Dictionary new)
        at: #Dependencies put: 15@145;
        at: #MaxRankSetSize put: 265@105;
        at: #RankedActivityList put: 180@175;
        at: #View put: 20@10;
        at: #MaxRank put: 335@30;
        yourself.
    ^dict.

" BB4bDependencyCtx class class methods in category: role structure "

roleStructure
    ^super roleStructure
    at: #Dependencies put: #();
    at: #MaxRankSetSize put: #();
    at: #RankedActivityList put: #();
    at: #View put: #(#RankedActivityList #MaxRank #Dependencies #MaxRankSetSize );
    at: #MaxRank put: #();
        yourself.

No diagram

" Methodless Role Dependencies "

" Methodless Role MaxRank "

" Methodless Role MaxRankSetSize "

" Methodless Role RankedActivityList "

" Methodful Role View "

run
    View addActivityViews.
    View addLines.

addLines
    | fromView toView pt1 pt2 |
    Dependencies do:
        [:dep |
        fromView := self activiyViewAt: dep predecessor.
        toView := self activiyViewAt: dep successor.
        pt1 := fromView right
                    @ ((fromView top + (fromView height // 2))).
        pt2 := toView left
                    @ ((toView top + (toView height // 2))).
        self addLineFrom: pt1 to: pt2.
        ].

addActivityViews
    | gridX gridY x0 y0 actViewExtent xPos yPos actView |
    gridX := self bounds width // MaxRank.
    gridY := self bounds height // MaxRankSetSize.
    x0 := self bounds left + 10.
    y0 := self bounds top + 10.
    actViewExtent := 100 @ 40. "(gridX-50) @ (gridY-20)."
    1 to: RankedActivityList size do:
        [:rank |
        xPos := x0 + (gridX * (rank-1)).
        yPos := y0.
        (RankedActivityList at: rank) do:
            [:act |
                actView := self addActivityViewFor: act.
                actView bounds: ((xPos @ yPos) extent: actViewExtent).
                yPos := yPos + gridY.
            ] ].


" Context: BB4bFrontloadCtx "

" Class BB4bFrontloadCtx "

" This Context selects an Activity that is ready for forntload planning and lets it play the Frontloader role in the Interaction.
It also computes its prdecessors, thus supporting the simple frontloader algorithm.

Instance variables:
    none.

See Controller>BB4bController for more information. "

BB1Context subclass: #BB4bFrontloadCtx
    instanceVariableNames: 'data projectStartWeek'
    classVariableNames: ''
    poolDictionaries: ''
    category: 'BB4bPlan-Context'

" BB4bFrontloadCtx instance methods in category: accessing "

data: aData
    data := aData.

" BB4bFrontloadCtx instance methods in category: data manipulation "

remap
    | messName |
    roleMap := self clearRoleMap.
    " Must do Activity first because Predecessors depend on it. "
    #(#Activity) , (self class roleNames copyWithout: #Activity) asArray
    do:
        [:rNam |
        messName := rNam asString asSymbol.
        roleMap at: messName put: (self perform: messName ifNotUnderstood: [nil])].

" BB4bFrontloadCtx instance methods in category: role binding "

Activity
    ^data allActivities
        detect:
            [:act |
            act earlyStart isNil
            and:
                [(data predecessorsOf: act) noneSatisfy: [:pred | pred earlyFinish isNil]]]
        ifNone: [nil]

AllActivities
    ^data allActivities

CurrentContext
    ^self

Frontloader
    ^data

Predecessors
    ^data predecessorsOf: (self at: #Activity)

ProjectStartWeek
    ^projectStartWeek

" BB4bFrontloadCtx instance methods in category: triggers "

data: model frontloadNetworkFrom: start
    data := model.
    projectStartWeek := 1.
    self runInteractionFromRoleNamed: #Frontloader.

" BB4bFrontloadCtx class class methods in category: context diagram "

linkBreakPoints
    | dict |
    (dict := Dictionary new)
        yourself.
    ^dict.

rolePositions
    | dict |
    (dict := Dictionary new)
        at: #AllActivities put: 205@125;
        at: #Activity put: 400@25;
        at: #Frontloader put: 110@25;
        at: #Predecessors put: 605@30;
        at: #ProjectStartWeek put: 355@125;
        at: #CurrentContext put: 25@125;
        yourself.
    ^dict.

" BB4bFrontloadCtx class class methods in category: role structure "

roleStructure
    ^super roleStructure
    at: #AllActivities put: #();
    at: #Activity put: #(#Predecessors #ProjectStartWeek );
    at: #Frontloader put: #(#Activity #CurrentContext #AllActivities );
    at: #Predecessors put: #();
    at: #ProjectStartWeek put: #();
    at: #CurrentContext put: #();
        yourself.

No diagram

" Methodful Role Activity "

frontload
        self earlyStart: ProjectStartWeek.
        Predecessors do:
            [:pred |
            (pred earlyFinish > self earlyStart)
                ifTrue: [self earlyStart: pred earlyFinish + 1]
            ].

frontloadFrom: projectStartWeek
        self earlyStart: projectStartWeek.
        Predecessors do:
            [:pred |
            (pred earlyFinish > self earlyStart)
                ifTrue: [self earlyStart: pred earlyFinish + 1]
            ].

" Methodless Role AllActivities "

" Methodless Role CurrentContext "

" Methodful Role Frontloader "

run
    AllActivities do: [:act | act resetForFrontload].
    [CurrentContext remap. Activity notNil]
    whileTrue:
        [Activity frontload].

" Methodless Role Predecessors "

" Methodless Role ProjectStartWeek "


" Context: BB4bGanttCtx "

" Class BB4bGanttCtx "

" This Context computes a number of values that support drawing the dependency diagram.
Let the cursor hover over the roles in the Interaction diagram to see how these values are computed.

The corresponding Interaction actually draws the diagram.
The presentation is simply based on rank where the rank of an activity is the max length of its predecessor chain.

Instance variables:
    view (GanttView) The roles are computed for this view.

See Controller>BB4bController for more information. "

BB1Context subclass: #BB4bGanttCtx
    instanceVariableNames: 'data view'
    classVariableNames: ''
    poolDictionaries: ''
    category: 'BB4bPlan-Context'

" BB4bGanttCtx instance methods in category: accessing "

data: aData
    data := aData.

" BB4bGanttCtx instance methods in category: initialization "

initialize
    super initialize.

view: v
    view := v.

" BB4bGanttCtx instance methods in category: role binding "

EndTime
    | time |
    time := nil.
    data allActivities do: [:act | time ifNil: [time := act earlyFinish] ifNotNil: [time := act earlyFinish max: time]].
    ^time ifNil: [0] ifNotNil: [time]

NameSortedActivities
    ^data allActivities asSortedCollection: [:x :y | x name < y name]

StartTime
    | time |
    time := nil.
    data allActivities do: [:act | time ifNil: [time := act earlyStart] ifNotNil: [time := act earlyStart min: time]].
    ^time ifNil: [0] ifNotNil: [time]

View
    ^view

" BB4bGanttCtx instance methods in category: triggers "

data: aData refresh: aView
    data := aData.
    view := aView.
    self runInteractionFromRoleNamed: #View.

" BB4bGanttCtx class class methods in category: context diagram "

linkBreakPoints
    | dict |
    (dict := Dictionary new)
        yourself.
    ^dict.

rolePositions
    | dict |
    (dict := Dictionary new)
        at: #StartTime put: 240@20;
        at: #NameSortedActivities put: 30@130;
        at: #View put: 10@20;
        at: #EndTime put: 235@95;
        yourself.
    ^dict.

" BB4bGanttCtx class class methods in category: role structure "

roleStructure
    ^super roleStructure
    at: #StartTime put: #();
    at: #NameSortedActivities put: #();
    at: #View put: #(#NameSortedActivities #StartTime #EndTime );
    at: #EndTime put: #();
        yourself.

No diagram

" Methodless Role EndTime "

" Methodless Role NameSortedActivities "

" Methodless Role StartTime "

" Methodful Role View "

run
    View addActivityViews.
    View addLines.

addLines
    | maxX maxY gridX gridY y1 y2 y0 |
    maxX := self width - 20.
    maxY := self height - 20.
    gridX := maxX // (EndTime - StartTime + 1).
    gridY := maxY // (NameSortedActivities size + 1).
    y0 := self top + 10.
    y1 := NameSortedActivities size * gridY + self top + 20.
    y2 := self bottom - 10.
    self addLineFrom: (self left + 10) @ y1 to: (self right - 10) @ y1.
    0 to: EndTime - StartTime + 1 do:
        [:week || x |
        x := week * gridX + self left + 10.
        self addLineFrom: x @ y0 to: x @ y2.
        self
            addAnnotationFor: (StartTime + week) printString
            at: (gridX // 2 + x) @ (y1 + 10).
        ].

addActivityViews
    | currY maxX maxY gridX gridY x0 width actView |
    StartTime = EndTime ifTrue: [^self. "Network not planned. "].
    maxX := self width - 20.
    maxY := self height - 20.
    gridX := maxX // (EndTime - StartTime + 1).
    gridY := maxY // (NameSortedActivities size + 1).
    currY := 10.
    NameSortedActivities do: [:act |
        x0 := act earlyStart - StartTime * gridX + 10.
        width := (act earlyFinish - act earlyStart + 1) * gridX.
        actView := self addActivityViewFor: act.
        actView bounds: ((x0+self left) @ ((currY+self top) + 1) extent: width @ (gridY-2)).        
        currY := currY + gridY].


" Controller perspective "

" Class BB4bController "

" This example is a DCI implementation of the BB4bPlan example.

The point of this example is to illustrate how system behavior code is separated according to system operation (use case)

This class is the C part of the original MVC paradigm:
    M is the Model that represents domain information
    V is a View that presents Model data to an end user and lets the user edit these data.
    C is a Controller that sets up and coordinates a number of Views. "

SystemWindow subclass: #BB4bController
    instanceVariableNames: 'dependencyView ganttView selectedActivity gofCollab'
    classVariableNames: ''
    poolDictionaries: ''
    category: 'BB4bPlan-Controller'

" BB4bController instance methods in category: overrides "

addMorph: aMorph fullFrame: aLayoutFrame
    " Suppresses crazy handling of panes in StandardSystemWindow. "
    | left right bottom top windowBorderWidth |
    windowBorderWidth _ self class borderWidth.
    left _ aLayoutFrame leftOffset ifNil: [0].
    right _ aLayoutFrame rightOffset ifNil: [0].
    bottom _ aLayoutFrame bottomOffset ifNil: [0].
    top _ aLayoutFrame topOffset ifNil: [0].
    aLayoutFrame rightFraction = 1 ifTrue: [aLayoutFrame rightOffset: right - windowBorderWidth].
    aLayoutFrame leftFraction = 0
        ifTrue: [aLayoutFrame leftOffset: left + windowBorderWidth]
        ifFalse: [aLayoutFrame leftOffset: left + ProportionalSplitterMorph splitterWidth].
    aLayoutFrame bottomFraction = 1 ifTrue: [aLayoutFrame bottomOffset: bottom - windowBorderWidth].
    aLayoutFrame topFraction = 0
        ifTrue: [aLayoutFrame topOffset: top]
        ifFalse: [aLayoutFrame topOffset: top + ProportionalSplitterMorph splitterWidth].
    (aMorph class name = #BrowserCommentTextMorph) ifTrue:
        [aLayoutFrame rightOffset: windowBorderWidth negated.
        aLayoutFrame leftOffset: windowBorderWidth.
        aLayoutFrame bottomOffset: windowBorderWidth negated.
        aLayoutFrame topOffset: (windowBorderWidth negated) + 4].
"    super addMorph: aMorph fullFrame: aLayoutFrame."
    aMorph layoutFrame: aLayoutFrame.
    aMorph hResizing: #spaceFill; vResizing: #spaceFill.
    self addMorph: aMorph.
    paneMorphs _ paneMorphs copyReplaceFrom: 1 to: 0 with: (Array with: aMorph).
"    aMorph adoptPaneColor: self paneColor."
"    aMorph borderWidth: 1; borderColor: Color lightGray; color: Color white."
    Preferences scrollBarsOnRight    "reorder panes so flop-out right-side scrollbar is visible"
        ifTrue: [self addMorphBack: aMorph].
    self addPaneSplitters.

open
    self buildDependencyView.
    self addMorph: dependencyView
        fullFrame: (LayoutFrame fractions: (0@0 corner: 1@0.4)).
    self buildGanttView.
    self addMorph: ganttView
        fullFrame: (LayoutFrame fractions: (0@0.4 corner: 1@1)).
    self openInWorld.
    model ifNotNil: [self changed: #model].

openInWorld: aWorld
    self bounds: (Rectangle originFromUser: 700@400).
    ^self openAsIsIn: aWorld

" BB4bController instance methods in category: private "

buildDependencyView
    (dependencyView := BB4bDependencyView new)
        color: Color lightGreen lighter;
        borderWidth: 2;
        borderColor: Color black;
        controller: self.

buildGanttView
    (ganttView := BB4bGanttView new)
        color: Color lightBlue lighter;
        borderWidth: 2;
        borderColor: Color black;
        controller: self.

" BB4bController instance methods in category: private-mouse "

handlesMouseDown: evt
    ^true

mouseDown: evt
    super mouseDown: evt.
    evt yellowButtonPressed
        ifTrue: [^self yellowButtonActivity: evt].

" BB4bController instance methods in category: selection "

clickAt: act
    selectedActivity := selectedActivity == act ifTrue: [nil] ifFalse: [act].
    self changed: #selection.

isSelected: act
    ^selectedActivity == act.

selectedActivity
    ^selectedActivity

selectedActivity: act
    selectedActivity := act.

" BB4bController instance methods in category: triggers "

buildDemoNetwork
    model ifNotNil: [self resetDemo].
    model := BB4bModel new.
    model
        newActivityNamed: 'actA' duration: 2 color: Color yellow;
        newActivityNamed: 'actB' duration: 7 color: Color lightBlue;
        newActivityNamed: 'actC' duration: 3 color: Color lightMagenta;
        newActivityNamed: 'actD' duration: 2 color: Color lightGreen.
    model
        newDependencyFrom: 'actA' to: 'actC';
        newDependencyFrom: 'actB' to: 'actD';
        newDependencyFrom: 'actC' to: 'actD'.
    self changed: #model.

frontloadDemo
    model ifNil: [self inform: 'Define the model before frontloading. \Command ignored.' withCRs. ^self].
    BB4bFrontloadCtx new data: model frontloadNetworkFrom: 1.
    self changed: #model.

resetDemo
    self model: nil.
    dependencyView deleteContents.
    ganttView deleteContents.

yellowButtonActivity: shiftKeyState
    | aMenu |
    aMenu := (MenuMorph new defaultTarget: self)
        addTitle: self printString;
        add: 'build demo network' action: #buildDemoNetwork;
        add: 'frontload from week 1' action: #frontloadDemo;
        add: 'reset demo' action: #resetDemo.
    aMenu popUpInWorld.

" BB4bController class class methods in category: class initialization "

initialize
    " BB4bController initialize "
    TheWorldMenu unregisterOpenCommand: 'BabyShapes animation'.
    TheWorldMenu
        registerOpenCommand:
            {'BB4bPlan with role and context'. {BB4bController. #open.}. 'Baby plan with role and context'}.

" BB4bController class class methods in category: instance creation "

open
    (self labelled: 'BB4bPlan') open.

" View perspective "

" Class BB4bActivityView "

" This class is a V part of the original MVC paradigm:
    M is the Model that represents domain information
    V is a View that presents Model data to an end user and lets the user edit these data.
    C is a Controller that sets up and coordinates a number of Views.
This View presents a single network activity.

See Controller>BB4bController for more information. "

RectangleMorph subclass: #BB4bActivityView
    instanceVariableNames: 'model controller activity nameMorph'
    classVariableNames: ''
    poolDictionaries: ''
    category: 'BB4bPlan-View'

" BB4bActivityView instance methods in category: access "

setModel: aGofObserver
    model := aGofObserver.
    model changed.

" BB4bActivityView instance methods in category: private "

borderColor
    ^self isSelected
        ifTrue: [Color red]
        ifFalse: [Color black]

borderWidth
    ^self isSelected
        ifTrue: [5]
        ifFalse: [2]

changed
    super changed.
    model ifNotNil: [model changed].

controller: cnt activity: act
    controller := cnt.
    activity := act.
    self color: act color.
    nameMorph
        newContents: '' asText;     " To block any TextMorph optimization if name unchanged. "
        newContents: activity displayName asText allBold;
        updateFromParagraph.
    self update: nil.
    self invalidRect: self bounds.

initialize
    super initialize.
    self
        borderWidth: 2;
        borderColor: Color black;
        layoutPolicy: (TableLayout new);
        hResizing: #rigid;
        vResizing: #rigid;
        color: Color gray;
        extent: 75@50.
    nameMorph := TextMorph new
            hResizing: #shrinkWrap;
            contents: '';
            wrapFlag: false;
            centered;
            margins: 10;
            yourself.
    self addMorphBack: nameMorph.

isSelected
    ^controller isSelected: activity

printOn: strm
    super printOn: strm.
    strm nextPutAll: ' (' , nameMorph text asString , ')'.

" BB4bActivityView instance methods in category: private-mouse "

click: evt
    controller clickAt: activity.

handlesMouseDown: evt
    ^true

mouseDown: evt
    evt yellowButtonPressed
        ifTrue: [^self yellowButtonActivity: evt].
    (evt redButtonPressed and: [self bounds containsPoint: evt cursorPoint])
        ifTrue: [evt hand waitForClicksOrDrag: self event: evt].

mouseDownPriority
    ^nameMorph mouseDownPriority + 1.

" BB4bActivityView instance methods in category: triggers "

update: aParameter
    aParameter = #selection
    ifTrue:
        [self borderWidth: self borderWidth.
        self color: self color.
        self borderColor: self borderColor.
    "    self invalidRect: self bounds."
        
        
"    self traceRM: {activity name. self borderColor.}."
    
    ].

" Class BB4bDependencyView "

" This class is a V part of the original MVC paradigm:
    M is the Model that represents domain information
    V is a View that presents Model data to an end user and lets the user edit these data.
    C is a Controller that sets up and coordinates a number of Views.
This View presents a an activity network as a graph.

The main difference from the plain BB4a solution is that we here get Model data presented through a Context (BB4bDependencyCtx) that transforms Model data to a form that is ideal for drawing this View.

See Controller>BB4bController for more information. "

PasteUpMorph subclass: #BB4bDependencyView
    instanceVariableNames: 'controller activityViews lines'
    classVariableNames: ''
    poolDictionaries: ''
    category: 'BB4bPlan-View'

" BB4bDependencyView instance methods in category: access "

activiyViewAt: act
    ^activityViews at: act

activiyViews
    ^activityViews values

addActivityViewFor: act
    | actView |
    actView := BB4bActivityView new controller: controller activity: act.
    activityViews at: act put: actView.
    self addMorph: actView.
    controller addDependent: actView.
    ^actView

addLineFrom: pt1 to: pt2
    | line |
    (line := PolygonMorph vertices: {pt1. pt2.} color: Color black borderWidth: 2 borderColor: Color black)
         makeOpen;
        sticky: true.
    lines add: line.
    self addMorph: line.

setModel: aGofObserver
    model := aGofObserver model.
    aGofObserver changed.

" BB4bDependencyView instance methods in category: private "

changed
    super changed.
    model ifNotNil: [model changed].

controller: cnt
    controller := cnt.
    controller addDependent: self.

deleteContents
    activityViews values do: [:p | p delete].
    activityViews := Dictionary new.
    lines do: [:lin | lin delete].
    lines := OrderedCollection new.
    self changed.

handlesMouseDown: evt
    ^false

initialize
    super initialize.
    activityViews := Dictionary new.
    lines := OrderedCollection new.

" BB4bDependencyView instance methods in category: triggers "

refresh
    self deleteContents.
    BB4bDependencyCtx new
        data: controller model
        refresh: self.

update: aSymbol
    aSymbol = #model ifTrue: [self refresh].

" BB4bDependencyView class class methods in category: instance creation "

data: aData view: aView
    ^self new data: aData; view: aView; yourself

" Class BB4bGanttView "

" This class is a V part of the original MVC paradigm:
    M is the Model that represents domain information
    V is a View that presents Model data to an end user and lets the user edit these data.
    C is a Controller that sets up and coordinates a number of Views.
This View presents the network activities along a time axis showing the time period of the execution of each activity.

The main difference from the plain BB4a solution is that we here get Model data presented through a Context (BB4bGanttCtx) that transforms Model data to a form that is ideal for drawing this View.

See Controller>BB4bController for more information. "

PasteUpMorph subclass: #BB4bGanttView
    instanceVariableNames: 'controller activityViews lines annotations'
    classVariableNames: ''
    poolDictionaries: ''
    category: 'BB4bPlan-View'

" BB4bGanttView instance methods in category: access "

addActivityViewFor: act
    | actView |
    actView := BB4bActivityView new controller: controller activity: act.
    activityViews at: act put: actView.
    self addMorph: actView.
    controller addDependent: actView.
    ^actView

setModel: aGofObserver
    model := aGofObserver.
    model changed.

" BB4bGanttView instance methods in category: initialization "

controller: cnt
    controller := cnt.
    controller addDependent: self.

initialize
    super initialize.
    activityViews := Dictionary new.
    lines := OrderedCollection new.
    annotations := OrderedCollection new.

" BB4bGanttView instance methods in category: private "

addAnnotationFor: aString at: pt
    | annot |
    annot := StringMorph
                contents: aString
                font: ( ((TextStyle named: 'BitstreamVeraSans') fontAt: 3))
                emphasis: 1.
    annot
        color: Color lightGray;
        position: pt.
    annotations add: annot.
    self addMorphBack: annot.

addLineFrom: pt1 to: pt2
    | line |
    (line := PolygonMorph vertices: {pt1. pt2.} color: Color black borderWidth: 2 borderColor: Color black)
         makeOpen;
        sticky: true;
        color: Color lightGray;
        borderColor: Color lightGray.
    lines add: line.
    self addMorphBack: line.

changed
    super changed.
    model ifNotNil: [model changed].

deleteContents
    activityViews values do: [:view | view delete].
    activityViews := Dictionary new.
    lines do: [:lin | lin delete].
    lines := OrderedCollection new.
    annotations do: [:ann | ann delete].
    annotations := OrderedCollection new.
    self changed.

" BB4bGanttView instance methods in category: triggers "

refresh
    self deleteContents.
    BB4bGanttCtx new data: controller model refresh: self.

update: aSymbol
    aSymbol = #model ifTrue: [self refresh].