1
- using System . ComponentModel ;
2
- using System . IO ;
3
- using System . Runtime . CompilerServices ;
4
- using System . Windows . Controls ;
5
- using System . Windows . Input ;
6
- using CodeParser . Extensions ;
1
+ using CodeParser . Extensions ;
7
2
using Contracts . Graph ;
8
3
using CSharpCodeAnalyst . Common ;
4
+ using CSharpCodeAnalyst . GraphArea . Highlighig ;
9
5
using CSharpCodeAnalyst . GraphArea . RenderOptions ;
10
6
using CSharpCodeAnalyst . Help ;
11
7
using Microsoft . Msagl . Drawing ;
12
8
using Microsoft . Msagl . WpfGraphControl ;
13
- using Color = Microsoft . Msagl . Drawing . Color ;
9
+ using System . ComponentModel ;
10
+ using System . IO ;
11
+ using System . Runtime . CompilerServices ;
12
+ using System . Windows . Controls ;
13
+ using System . Windows . Input ;
14
14
using Node = Microsoft . Msagl . Drawing . Node ;
15
15
16
16
namespace CSharpCodeAnalyst . GraphArea ;
@@ -35,20 +35,10 @@ internal partial class DependencyGraphViewer : IDependencyGraphViewer, IDependen
35
35
/// Held to read the help
36
36
/// </summary>
37
37
private IViewerObject ? _clickedObject ;
38
-
39
38
private CodeGraph _clonedCodeGraph = new ( ) ;
40
-
41
-
42
39
private IQuickInfoFactory ? _factory ;
43
-
44
- private HighlightMode _highlightMode ;
45
- private Color _lastHighlightedColor ;
46
-
47
- private IViewerEdge ? _lastHighlightedEdge ;
48
-
49
40
private GraphViewer ? _msaglViewer ;
50
41
private PresentationState _presentationState = new ( ) ;
51
-
52
42
private RenderOption _renderOption = new DefaultRenderOptions ( ) ;
53
43
private bool _showFlatGraph ;
54
44
@@ -64,7 +54,6 @@ public DependencyGraphViewer(IPublisher publisher)
64
54
_msaglBuilder = new MsaglBuilder ( ) ;
65
55
SetHighlightMode ( HighlightMode . EdgeHovered ) ;
66
56
}
67
-
68
57
public void Bind ( Panel graphPanel )
69
58
{
70
59
_msaglViewer = new GraphViewer ( ) ;
@@ -96,7 +85,6 @@ private void AddToGraphInternal(IEnumerable<CodeElement> originalCodeElements, I
96
85
sourceElement . Dependencies . Add ( newDependency ) ;
97
86
}
98
87
99
-
100
88
RefreshGraph ( ) ;
101
89
}
102
90
@@ -141,9 +129,8 @@ private void Clear(bool withUndoStack)
141
129
}
142
130
public void Clear ( )
143
131
{
144
- Clear ( true ) ;
132
+ Clear ( true ) ;
145
133
}
146
-
147
134
private void ClearUndo ( )
148
135
{
149
136
_undoStack . Clear ( ) ;
@@ -179,11 +166,24 @@ public void SaveToSvg(FileStream stream)
179
166
180
167
public void SetHighlightMode ( HighlightMode valueMode )
181
168
{
182
- _highlightMode = valueMode ;
183
- ClearEdgeColoring ( ) ;
169
+ _activeHighlighting ? . Clear ( _msaglViewer ) ;
170
+ switch ( valueMode )
171
+ {
172
+ case HighlightMode . EdgeHovered :
173
+ _activeHighlighting = new EdgeHoveredHighlighting ( ) ;
174
+ break ;
175
+ case HighlightMode . OutgoingEdgesChildrenAndSelf :
176
+ _activeHighlighting = new OutgointEdgesOfChildrenAndSelfHighlighting ( ) ;
177
+ break ;
178
+ case HighlightMode . ShortestNonSelfCircuit :
179
+ _activeHighlighting = new HighligtShortestNonSelfCircuit ( ) ;
180
+ break ;
181
+ default :
182
+ _activeHighlighting = new EdgeHoveredHighlighting ( ) ;
183
+ break ;
184
+ }
184
185
}
185
186
186
-
187
187
public void SetQuickInfoFactory ( IQuickInfoFactory factory )
188
188
{
189
189
_factory = factory ;
@@ -207,23 +207,91 @@ public void ShowGlobalContextMenu()
207
207
globalContextMenu . Items . Add ( item ) ;
208
208
209
209
210
- item = new MenuItem { Header = "Delete all marked elements " } ;
210
+ item = new MenuItem { Header = "Delete marked (with children) " } ;
211
211
item . Click += ( _ , _ ) => DeleteAllMarkedElements ( ) ;
212
212
globalContextMenu . Items . Add ( item ) ;
213
213
214
+
215
+ item = new MenuItem { Header = "Focus on marked elements" } ;
216
+ item . Click += ( _ , _ ) => FocusOnMarkedElements ( ) ;
217
+ globalContextMenu . Items . Add ( item ) ;
218
+
214
219
globalContextMenu . IsOpen = true ;
215
220
}
216
221
222
+ private void DeleteAllMarkedElements ( )
223
+ {
224
+ if ( _msaglViewer is null )
225
+ {
226
+ return ;
227
+ }
228
+
229
+ PushUndo ( ) ;
230
+
231
+ var ids = _msaglViewer . Entities . Where ( e => e . MarkedForDragging ) . OfType < IViewerNode > ( ) . Select ( n => n . Node . Id ) ;
232
+
233
+ var idsToRemove = ids . ToHashSet ( ) ;
234
+
235
+ // All children
236
+ foreach ( var id in ids )
237
+ {
238
+ var children = _clonedCodeGraph . Nodes [ id ] . GetChildrenIncludingSelf ( ) ;
239
+ idsToRemove . UnionWith ( children ) ;
240
+ }
241
+
242
+ _clonedCodeGraph . RemoveCodeElements ( idsToRemove ) ;
243
+ _presentationState . RemoveStates ( idsToRemove ) ;
244
+
245
+ RefreshGraph ( ) ;
246
+ }
247
+
248
+ private void FocusOnMarkedElements ( )
249
+ {
250
+ // We want to include all children of the collapsed code elements
251
+ // and keep also the presentation state. Just less information
252
+
253
+ if ( _msaglViewer is null )
254
+ {
255
+ return ;
256
+ }
257
+
258
+ var ids = _msaglViewer . Entities
259
+ . Where ( e => e . MarkedForDragging )
260
+ . OfType < IViewerNode > ( ) . Select ( n => n . Node . Id ) ;
261
+
262
+ if ( ids . Any ( ) is false )
263
+ {
264
+ return ;
265
+ }
266
+
267
+ PushUndo ( ) ;
268
+ var idsToKeep = ids . ToHashSet ( ) ;
269
+
270
+ // All children
271
+ foreach ( var id in ids )
272
+ {
273
+ var children = _clonedCodeGraph . Nodes [ id ] . GetChildrenIncludingSelf ( ) ;
274
+ idsToKeep . UnionWith ( children ) ;
275
+ }
276
+
277
+ var newGraph = _clonedCodeGraph . SubGraphOf ( idsToKeep ) ;
278
+
279
+ // Cleanup unused states
280
+ var idsToRemove = _clonedCodeGraph . Nodes . Keys . Except ( idsToKeep ) . ToHashSet ( ) ;
281
+ _presentationState . RemoveStates ( idsToRemove ) ;
282
+
283
+ _clonedCodeGraph = newGraph ;
284
+ RefreshGraph ( ) ;
285
+ }
217
286
218
-
219
287
public bool Undo ( )
220
288
{
221
289
if ( _undoStack . Any ( ) is false )
222
290
{
223
291
return false ;
224
292
}
225
293
226
- var state = _undoStack . First ( ) ;
294
+ var state = _undoStack . First ( ) ;
227
295
_undoStack . RemoveFirst ( ) ;
228
296
229
297
_clonedCodeGraph = state . CodeGraph ;
@@ -244,7 +312,6 @@ public void ImportCycleGroup(List<CodeElement> codeElements, List<Dependency> de
244
312
AddToGraphInternal ( codeElements , dependencies ) ;
245
313
}
246
314
247
-
248
315
public event PropertyChangedEventHandler ? PropertyChanged ;
249
316
250
317
private void PushUndo ( )
@@ -259,20 +326,6 @@ private void PushUndo()
259
326
_undoStack . AddFirst ( state ) ;
260
327
}
261
328
262
- private void ClearEdgeColoring ( )
263
- {
264
- if ( _msaglViewer is null )
265
- {
266
- return ;
267
- }
268
-
269
- var edges = _msaglViewer . Entities . OfType < IViewerEdge > ( ) ;
270
- foreach ( var edge in edges )
271
- {
272
- edge . Edge . Attr . Color = Color . Black ;
273
- }
274
- }
275
-
276
329
/// <summary>
277
330
/// Adds the new nodes, integrating hierarchical relationships from
278
331
/// original master nodes. Parent / child connections not present in this graph are discarded.
@@ -288,7 +341,6 @@ private void IntegrateNewFromOriginal(IEnumerable<CodeElement> originalCodeEleme
288
341
}
289
342
}
290
343
291
-
292
344
private void DeleteNode ( Node node )
293
345
{
294
346
if ( _msaglViewer is null )
@@ -317,24 +369,8 @@ private void RefreshGraph()
317
369
}
318
370
}
319
371
320
- private void HighlightEdge ( IViewerEdge ? newEdge )
321
- {
322
- // Reset last highlighted edge
323
- if ( _lastHighlightedEdge != null )
324
- {
325
- _lastHighlightedEdge . Edge . Attr . Color = _lastHighlightedColor ;
326
- _msaglViewer ? . Invalidate ( _lastHighlightedEdge ) ;
327
- }
328
372
329
- // Highlight new edge, if any
330
- if ( newEdge != null )
331
- {
332
- _lastHighlightedColor = newEdge . Edge . Attr . Color ;
333
- _lastHighlightedEdge = newEdge ;
334
- newEdge . Edge . Attr . Color = Color . Red ;
335
- _msaglViewer ? . Invalidate ( newEdge ) ;
336
- }
337
- }
373
+ IHighlighting _activeHighlighting = new EdgeHoveredHighlighting ( ) ;
338
374
339
375
private void ObjectUnderMouseCursorChanged ( object ? sender , ObjectUnderMouseCursorChangedEventArgs e )
340
376
{
@@ -344,45 +380,7 @@ private void ObjectUnderMouseCursorChanged(object? sender, ObjectUnderMouseCurso
344
380
UpdateQuickInfoPanel ( e . NewObject ) ;
345
381
}
346
382
347
- if ( _highlightMode == HighlightMode . EdgeHovered )
348
- {
349
- HighlightEdge ( e . NewObject as IViewerEdge ) ;
350
- }
351
-
352
- if ( _highlightMode == HighlightMode . OutgoingEdgesChildrenAndSelf )
353
- {
354
- HighlightOutgoingEdgesOfChildrenAndSelf ( e . NewObject as IViewerNode ) ;
355
- }
356
- }
357
-
358
- private void HighlightOutgoingEdgesOfChildrenAndSelf ( IViewerNode ? node )
359
- {
360
- if ( _msaglViewer is null )
361
- {
362
- return ;
363
- }
364
-
365
- var ids = new HashSet < string > ( ) ;
366
- if ( node != null )
367
- {
368
- var id = node . Node . Id ;
369
- var vertex = _clonedCodeGraph . Nodes [ id ] ;
370
- ids = vertex . GetChildrenIncludingSelf ( ) ;
371
- }
372
-
373
- var edges = _msaglViewer . Entities . OfType < IViewerEdge > ( ) ;
374
- foreach ( var edge in edges )
375
- {
376
- var sourceId = edge . Edge . Source ;
377
- if ( ids . Contains ( sourceId ) )
378
- {
379
- edge . Edge . Attr . Color = Color . Red ;
380
- }
381
- else
382
- {
383
- edge . Edge . Attr . Color = Color . Black ;
384
- }
385
- }
383
+ _activeHighlighting . Highlight ( _msaglViewer , e . NewObject , _clonedCodeGraph ) ;
386
384
}
387
385
388
386
private void OnPropertyChanged ( [ CallerMemberName ] string ? name = null )
@@ -434,7 +432,6 @@ bool IsCtrlPressed()
434
432
}
435
433
}
436
434
437
-
438
435
if ( e . RightButtonIsPressed )
439
436
{
440
437
if ( _msaglViewer ? . ObjectUnderMouseCursor is not IViewerNode clickedObject )
@@ -532,33 +529,24 @@ private void Expand(string id)
532
529
RefreshGraph ( ) ;
533
530
}
534
531
535
- private void DeleteAllMarkedElements ( )
536
- {
537
- if ( _msaglViewer is null )
538
- {
539
- return ;
540
- }
541
532
542
- var ids = _msaglViewer . Entities . Where ( e => e . MarkedForDragging ) . OfType < IViewerNode > ( ) . Select ( n => n . Node . Id ) ;
543
- foreach ( var id in ids )
544
- {
545
- _clonedCodeGraph . RemoveCodeElement ( id ) ;
546
- }
547
-
548
- RefreshGraph ( ) ;
549
- }
550
533
551
534
private void AddMissingDependencies ( )
552
535
{
536
+ PushUndo ( ) ;
537
+
538
+ // We do not know the original graph.
553
539
_publisher . Publish ( new AddMissingDependenciesRequest ( ) ) ;
554
540
}
555
541
556
542
private void AddParentRequest ( Node node )
557
543
{
544
+ PushUndo ( ) ;
545
+
546
+ // We do not know the original graph.
558
547
_publisher . Publish ( new AddParentContainerRequest ( node . Id ) ) ;
559
548
}
560
549
561
-
562
550
private void FindInTree ( Node node )
563
551
{
564
552
_publisher . Publish ( new LocateInTreeRequest ( node . Id ) ) ;
0 commit comments