• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

moosetechnology / MooseIDE / 18785237627

24 Oct 2025 04:01PM UTC coverage: 66.57% (-0.06%) from 66.63%
18785237627

push

github

web-flow
Merge pull request #1492 from moosetechnology/settings-toolbar

Improve save and load settings UX in MiSettingsPresenter

20 of 43 new or added lines in 1 file covered. (46.51%)

17 existing lines in 3 files now uncovered.

20732 of 31143 relevant lines covered (66.57%)

1.33 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

95.44
/src/MooseIDE-CoUsageMap/MiCoUsageMapModel.class.st
1
"
2
A model for the CoUsageMap browser
3
"
4
Class {
5
        #name : #MiCoUsageMapModel,
6
        #superclass : #MiAbstractModel,
7
        #instVars : [
8
                'settingsWindow',
9
                'containerEntities',
10
                'selectedEntity',
11
                'methodAttributeCounter',
12
                'innerBoxes',
13
                'containerBoxes',
14
                'widthScale'
15
        ],
16
        #category : #'MooseIDE-CoUsageMap-Model'
17
}
18

19
{ #category : #tagging }
20
MiCoUsageMapModel >> automaticColor [
2✔
21

2✔
22
        self changeTagsDuring: [ 
2✔
23
                self containerBoxes
2✔
24
                        do: [:met | self automaticColorForContainerBox: met ].
2✔
25
        ]
2✔
26
        
2✔
27
]
2✔
28

29
{ #category : #tagging }
30
MiCoUsageMapModel >> automaticColorForContainerBox: aMiContainer [
2✔
31
        "inner boxes are grouped by their tag (#groupsByTag)
2✔
32
         If there are several groups, searches for the largest (ignoring the group of untagged)
2✔
33
         then checks whether it size is >= threshold percent of all inner boxes.
2✔
34
         If so, set the tag on aMiContainer"
2✔
35

2✔
36
        | groupsByTag tag |
2✔
37

2✔
38
        groupsByTag := aMiContainer innerBoxes groupedBy: [ :att | att tag ].
2✔
39
        groupsByTag ifEmpty: [ ^ self ].
2✔
40
        
2✔
41
        tag := self largestTag: groupsByTag in: aMiContainer.
2✔
42

2✔
43
        "note: tag could be nil here if we did not find a large enough group"
2✔
44
        self setTag: tag onInnerBox: aMiContainer.
2✔
45

2✔
46
]
2✔
47

48
{ #category : #tagging }
49
MiCoUsageMapModel >> changeTagsDuring: aBlockClosure [
2✔
50
        | lastTag |
2✔
51
        lastTag := self selectedTag.
2✔
52
        aBlockClosure value.
2✔
53
        self selectedTag: lastTag
2✔
54
]
2✔
55

56
{ #category : #'private - for tests' }
57
MiCoUsageMapModel >> closeSettings [
×
58
        "used only for closing settings opened in tests"
×
59
        settingsWindow ifNotNil: [ settingsWindow close ]
×
60
]
×
61

62
{ #category : #accessing }
63
MiCoUsageMapModel >> containerBoxNamed: aByteString [
2✔
64
        ^ self containerBoxes detect: [ :contr | contr name = aByteString ]
2✔
65
]
2✔
66

67
{ #category : #accessing }
68
MiCoUsageMapModel >> containerBoxes [
2✔
69
        ^containerBoxes
2✔
70
]
2✔
71

72
{ #category : #accessing }
73
MiCoUsageMapModel >> containerEntities [
2✔
74
        ^ containerEntities
2✔
75
]
2✔
76

77
{ #category : #accessing }
78
MiCoUsageMapModel >> containerEntities: aCollection [
2✔
79
        containerEntities := aCollection
2✔
80
]
2✔
81

82
{ #category : #accessing }
83
MiCoUsageMapModel >> containerInnerCounter [
2✔
84

2✔
85
        ^ methodAttributeCounter
2✔
86
]
2✔
87

88
{ #category : #accessing }
89
MiCoUsageMapModel >> containerInnerCounter: aMiCoMethodAttributeCounter [
2✔
90
        methodAttributeCounter := aMiCoMethodAttributeCounter
2✔
91
]
2✔
92

93
{ #category : #settings }
UNCOV
94
MiCoUsageMapModel >> defaultInnerSortBlock [
×
UNCOV
95
        ^ [ :inner1 :inner2 :containr | inner1 name < inner2 name ].
×
UNCOV
96
]
×
97

98
{ #category : #settings }
99
MiCoUsageMapModel >> defaultSettings [
×
100
        ^ MiCoUsageMapSettings
×
101
]
×
102

103
{ #category : #settings }
104
MiCoUsageMapModel >> defaultSortBlock [
2✔
105
        ^ [ :container1 :container2 | 
2✔
106
                | size1 size2 |
2✔
107
                size1 := container1 innerBoxes size.
2✔
108
                size2 := container2 innerBoxes size.
2✔
109
                size1 = size2 
2✔
110
                        ifTrue: [ container1 name < container2 name ]
2✔
111
                        ifFalse: [ size1 > size2 ]
2✔
112
                 ].
2✔
113
]
2✔
114

115
{ #category : #settings }
116
MiCoUsageMapModel >> defaultTester [
2✔
117
        ^ MiCoFromSettingsMethodAttributeTester new
2✔
118
]
2✔
119

120
{ #category : #accessing }
121
MiCoUsageMapModel >> entities [
2✔
122
        ^containerEntities
2✔
123
]
2✔
124

125
{ #category : #actions }
126
MiCoUsageMapModel >> followEntity: aCollection [
2✔
127

2✔
128
        self containerEntities: aCollection.
2✔
129
        self initializeValues.
2✔
130
        browser runVisualization
2✔
131
]
2✔
132

133
{ #category : #accessing }
134
MiCoUsageMapModel >> getBoxFor: object [
2✔
135
        ^(self getContainerBoxFor: object) ifNil: [ self getInnerBoxFor: object ]
2✔
136
]
2✔
137

138
{ #category : #accessing }
139
MiCoUsageMapModel >> getContainerBoxFor: object [
2✔
140
        ^self containerBoxes
2✔
141
                detect: [ :box | box mooseEntity = object ]
2✔
142
                ifNone: [ nil ]
2✔
143
]
2✔
144

145
{ #category : #accessing }
146
MiCoUsageMapModel >> getInnerBoxFor: object [
2✔
147
        ^self innerBoxes
2✔
148
                detect: [ :inner | inner mooseEntity = object ]
2✔
149
                ifNone: [ nil ]
2✔
150
]
2✔
151

152
{ #category : #accessing }
153
MiCoUsageMapModel >> getInnerBoxNamed: aByteString [
2✔
154
        ^ self innerBoxes detect: [ :box | box name = aByteString ]
2✔
155
]
2✔
156

157
{ #category : #accessing }
158
MiCoUsageMapModel >> getOrCreateInnerBoxFor: object [
2✔
159

2✔
160
        ^ (self getInnerBoxFor: object)
2✔
161
                ifNil: [ innerBoxes add: (self newInnerBoxFor: object) ]
2✔
162
]
2✔
163

164
{ #category : #initialization }
165
MiCoUsageMapModel >> initialize [
2✔
166
        super initialize.
2✔
167

2✔
168
        self containerInnerCounter: self defaultTester
2✔
169
]
2✔
170

171
{ #category : #initialization }
172
MiCoUsageMapModel >> initializeContainerBoxes [
2✔
173

2✔
174
        containerBoxes := self containerEntities 
2✔
175
                collect: [ :cont | self newContainerBoxFor: cont ]
2✔
176
                as: OrderedCollection.
2✔
177
]
2✔
178

179
{ #category : #initialization }
180
MiCoUsageMapModel >> initializeReferences [
2✔
181
        innerBoxes := OrderedCollection new.
2✔
182

2✔
183
        self containerInnerCounter settings: self settings.
2✔
184
        
2✔
185
        self containerBoxes do: [ :cont | 
2✔
186
                | bag |
2✔
187
                bag := Bag withAll: (self containerInnerCounter allAttributesFor: cont).
2✔
188
                bag doWithOccurrences: [ :innerEntity :count | | in |
2✔
189
                        count > 0 ifTrue: [ 
2✔
190
                                in := self getOrCreateInnerBoxFor: innerEntity.
2✔
191
                                cont addInnerBox: in.
2✔
192
                                in containerBox: cont numberOfUses: count.
2✔
193
                        ].
2✔
194
                ].
2✔
195
        ]
2✔
196
]
2✔
197

198
{ #category : #initialization }
199
MiCoUsageMapModel >> initializeScale [
2✔
200
        | allInnerUses range scaleType cls |
2✔
201

2✔
202
        allInnerUses := self containerBoxes flatCollect: [ :cont | 
2✔
203
                cont innerBoxes collect: [ :inner | inner numberOfUses ] ].
2✔
204
        cls := MiCoUsageMapSettings.
2✔
205
        range := cls innerBoxRange.
2✔
206
        scaleType := cls innerBoxScaleType.
2✔
207
        
2✔
208
        widthScale := (scaleType value: NSScale)
2✔
209
                range: {range first. range last}.
2✔
210
        allInnerUses ifEmpty: [ ^ self ].
2✔
211
        widthScale domain: {allInnerUses min. allInnerUses max}.
2✔
212
]
2✔
213

214
{ #category : #initialization }
215
MiCoUsageMapModel >> initializeValues [
2✔
216
        self
2✔
217
                initializeContainerBoxes;
2✔
218
                initializeReferences;
2✔
219
                initializeScale.
2✔
220
]
2✔
221

222
{ #category : #settings }
223
MiCoUsageMapModel >> innerBoxHeight [
2✔
224
        ^self settings innerBoxHeight
2✔
225
]
2✔
226

227
{ #category : #settings }
228
MiCoUsageMapModel >> innerBoxSortBlockCompiled [
2✔
229
        ^self settings innerBoxSortBlockCompiled
2✔
230
]
2✔
231

232
{ #category : #accessing }
233
MiCoUsageMapModel >> innerBoxes [
2✔
234
        ^ innerBoxes
2✔
235
]
2✔
236

237
{ #category : #tagging }
238
MiCoUsageMapModel >> largestTag: groupsByTag in: containerBox [
2✔
239
        "inner boxes are grouped by their tag (#groupsByTag)
2✔
240
         search the largest of these groups (ignoring the group of untagged)
2✔
241
         then checks whether it size is >= threshold percent of all inner boxes.
2✔
242
         If so, returns the tag of this group"
2✔
243

2✔
244
        | largestGroup tag |
2✔
245
        tag := nil.
2✔
246
        largestGroup := 0.
2✔
247

2✔
248
        groupsByTag keysAndValuesDo: [ :groupTag :group | 
2✔
249
                ((groupTag isNotNil) and: [group size > largestGroup ])
2✔
250
                ifTrue: [
2✔
251
                        tag := groupTag.
2✔
252
                        largestGroup := group size ] ].
2✔
253

2✔
254
        ^(largestGroup / containerBox innerBoxes size) >= self threshold 
2✔
255
                ifTrue: [ tag ]
2✔
256
                ifFalse: [ nil ]
2✔
257
]
2✔
258

259
{ #category : #accessing }
260
MiCoUsageMapModel >> miSelectedItem [
×
261
        ^selectedEntity
×
262
]
×
263

264
{ #category : #'instance creation' }
265
MiCoUsageMapModel >> newContainerBoxFor: anObject [
2✔
266
        "| tags |
2✔
267
        tags := anObject allTagAssociations collect: [ :asso | asso tag ].
2✔
268
        tags := tags
2✔
269
                ifEmpty: [ nil ]
2✔
270
                ifNotEmpty: [ tags anyOne ]."
2✔
271
        ^ MiCoContainerBox new
2✔
272
                mooseEntity: anObject;
2✔
273
                yourself
2✔
274
]
2✔
275

276
{ #category : #'instance creation' }
277
MiCoUsageMapModel >> newInnerBoxFor: anObject [
2✔
278
        | tags |
2✔
279
        tags := anObject allTagAssociations collect: [ :asso | asso tag ].
2✔
280
        tags := tags
2✔
281
                ifEmpty: [ nil ]
2✔
282
                ifNotEmpty: [ tags anyOne ].
2✔
283
        ^ MiCoInnerBox new
2✔
284
                mooseEntity: anObject;
2✔
285
                yourself
2✔
286
]
2✔
287

288
{ #category : #settings }
289
MiCoUsageMapModel >> openSettings [
2✔
290
        "For now, we handle settings here:
2✔
291
         - create the window 
2✔
292
         - subscribe to be informed when any window is closed closed
2✔
293
         - if this is the setting window that is closed
2✔
294
            - unsubscribe to ALL announcements
2✔
295
            - update the visualization"
2✔
296

2✔
297
        | settingBrowser |
2✔
298
        settingBrowser := SettingBrowser new.
2✔
299
        settingBrowser changePackageSet: (OrderedCollection with:
2✔
300
                         (self packageOrganizer packageNamed:
2✔
301
                                  MiCoUsageMapSettings package name)).
2✔
302
        settingsWindow := settingBrowser open.
2✔
303
        settingsWindow position:
2✔
304
                self currentWorld extent - settingsWindow extent // 2.
2✔
305
        settingBrowser expandAll.
2✔
306

2✔
307
        self currentWorld announcer
2✔
308
                when: WindowClosed
2✔
309
                do: [ :annoucement |
2✔
310
                                annoucement window = settingsWindow ifTrue: [
2✔
311
                                                self currentWorld announcer unsubscribe: self.
2✔
312
                                                browser runVisualization ] ]
2✔
313
                for: self.
2✔
314
        ^ settingsWindow
2✔
315
]
2✔
316

317
{ #category : #settings }
318
MiCoUsageMapModel >> outerBoxSortBlockCompiled [
2✔
319
        ^self settings outerBoxSortBlockCompiled
2✔
320
]
2✔
321

322
{ #category : #events }
323
MiCoUsageMapModel >> quickTaggingOn: entity [ 
2✔
324

2✔
325
        self selectedTag
2✔
326
        ifNil: [ ^ self ]
2✔
327
        ifNotNil: [ :tag | self setTag: tag onInnerBox: entity ]
2✔
328

2✔
329
]
2✔
330

331
{ #category : #tagging }
332
MiCoUsageMapModel >> removeTagOn: aMooseEntity [
2✔
333
        aMooseEntity allTags
2✔
334
                detect: [ :aTag | aTag isHidden not ]
2✔
335
                ifOne: [ :aTag | aTag removeReference: aMooseEntity ]
2✔
336
                ifNone: [ "nothing" ]
2✔
337
]
2✔
338

339
{ #category : #accessing }
340
MiCoUsageMapModel >> selectedEntity [
2✔
341
        ^selectedEntity
2✔
342
]
2✔
343

344
{ #category : #accessing }
345
MiCoUsageMapModel >> selectedEntity: aMooseEntity [
2✔
346

2✔
347
        selectedEntity := aMooseEntity
2✔
348
]
2✔
349

350
{ #category : #tagging }
351
MiCoUsageMapModel >> setTag: aTag onInnerBox: aBox [
2✔
352

2✔
353
        self flag: #FIXME.
2✔
354
        "- #tagEntity:with: already calls #selectedTag:
2✔
355
         - #tagEntity:with: calls #getBoxFor: to find back aBox"
2✔
356

2✔
357
        self selectedTag: aTag.
2✔
358
        self tagEntity: aBox mooseEntity with: aTag
2✔
359
]
2✔
360

361
{ #category : #settings }
362
MiCoUsageMapModel >> settings [
2✔
363
        self flag: #FIXME.
2✔
364
        "settings should not be handled by a an other class (with only class side methods"
2✔
365

2✔
366
        ^MiCoUsageMapSettings
2✔
367
]
2✔
368

369
{ #category : #tagging }
370
MiCoUsageMapModel >> tagEntity: aMooseEntity with: aTag [
2✔
371
        "entites can have only one tag in this tool"
2✔
372

2✔
373
        self removeTagOn: aMooseEntity.
2✔
374

2✔
375
        super tagEntity: aMooseEntity with: aTag.
2✔
376

2✔
377
        browser updateBoxColor: (self getBoxFor: aMooseEntity) fromTags: aMooseEntity allTags.
2✔
378
        self selectedTag: aTag
2✔
379
]
2✔
380

381
{ #category : #settings }
382
MiCoUsageMapModel >> threshold [
2✔
383

2✔
384
        ^self settings threshold75PercentGroup/100.0
2✔
385
]
2✔
386

387
{ #category : #accessing }
388
MiCoUsageMapModel >> widthScale [
2✔
389
        ^ widthScale
2✔
390
]
2✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc