1
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
2
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
5
using System.Collections.Generic;
8
using System.Drawing.Drawing2D;
11
using System.Xml.XPath;
13
using ICSharpCode.SharpDevelop;
14
using ICSharpCode.SharpDevelop.Dom;
15
using ICSharpCode.SharpDevelop.Project;
17
using System.Globalization;
20
using Tools.Diagrams.Drawables;
22
namespace ClassDiagram
24
public class ClassCanvasItem : CanvasItem, IDisposable
28
InteractiveHeaderedItem classItemHeaderedContent;
29
DrawableItemsStack classItemContainer = new DrawableItemsStack();
31
#region Graphics related variables
33
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")]
34
public static readonly Font TitleFont = new Font (FontFamily.GenericSansSerif, 11, FontStyle.Bold, GraphicsUnit.Pixel);
35
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")]
36
public static readonly Font SubtextFont = new Font (FontFamily.GenericSansSerif, 11, FontStyle.Regular, GraphicsUnit.Pixel);
37
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")]
38
public static readonly Font GroupTitleFont = new Font (FontFamily.GenericSansSerif, 11, FontStyle.Regular, GraphicsUnit.Pixel);
40
LinearGradientBrush grad;
41
GraphicsPath shadowpath;
42
DrawableRectangle containingShape;
46
CollapseExpandShape collapseExpandShape = new CollapseExpandShape();
48
DrawableItemsStack titles = new DrawableItemsStack();
50
DrawableItemsStack titlesCollapsed = new DrawableItemsStack();
51
DrawableItemsStack titlesExpanded = new DrawableItemsStack();
53
DrawableItemsStack<InteractiveHeaderedItem> groups = new DrawableItemsStack<InteractiveHeaderedItem>();
54
Dictionary<InteractiveHeaderedItem, string> groupNames = new Dictionary<InteractiveHeaderedItem, string>(); // TODO - this is really an ugly patch
55
Dictionary<string, InteractiveHeaderedItem> groupsByName = new Dictionary<string, InteractiveHeaderedItem>(); // TODO - this is really an ugly patch
57
DrawableItemsStack<TextSegment> interfaces = new DrawableItemsStack<TextSegment>();
59
DrawableRectangle titlesBackgroundCollapsed;
60
DrawableRectangle titlesBackgroundExpanded;
62
protected override bool AllowHeightModifications()
67
public override float Width
71
base.Width = Math.Max (value, 100.0f);
76
public override float GetAbsoluteContentWidth()
78
return classItemHeaderedContent.GetAbsoluteContentWidth();
81
public override float GetAbsoluteContentHeight()
83
return classItemHeaderedContent.GetAbsoluteContentHeight();
86
public IClass RepresentedClassType
88
get { return classtype; }
93
public ClassCanvasItem (IClass ct)
97
grad = new LinearGradientBrush(
98
new PointF(0, 0), new PointF(1, 0),
99
TitleBackground, Color.White);
101
classItemHeaderedContent = new InteractiveHeaderedItem(titlesCollapsed, titlesExpanded, InitContentContainer(InitContent()));
103
classItemContainer.Container = this;
104
classItemContainer.Add(classItemHeaderedContent);
105
Pen outlinePen = GetClassOutlinePen();
108
int radius = CornerRadius;
109
containingShape = new DrawableRectangle(null, outlinePen, radius, radius, radius, radius);
112
containingShape = new DrawableRectangle(null, outlinePen, 0, 0, 0, 0);
114
classItemContainer.Add(containingShape);
115
classItemContainer.OrientationAxis = Axis.Z;
119
int radius = CornerRadius;
120
titlesBackgroundCollapsed = new DrawableRectangle(grad, null, radius, radius, radius, radius);
121
titlesBackgroundExpanded = new DrawableRectangle(grad, null, radius, radius, 0, 0);
125
titlesBackgroundCollapsed = new DrawableRectangle(grad, null, 0, 0, 0, 0);
126
titlesBackgroundExpanded = new DrawableRectangle(grad, null, 0, 0, 0, 0);
131
titlesCollapsed.Add(titlesBackgroundCollapsed);
132
titlesCollapsed.Add(titles);
133
titlesCollapsed.OrientationAxis = Axis.Z;
135
titlesExpanded.Add(titlesBackgroundExpanded);
136
titlesExpanded.Add(titles);
137
titlesExpanded.OrientationAxis = Axis.Z;
139
if (classtype != null)
141
typeclass = classtype.Modifiers.ToString();
142
typeclass += " " + classtype.ClassType.ToString();
148
private Pen GetClassOutlinePen()
150
Pen pen = new Pen(Color.Gray);
152
if (classtype.IsAbstract)
154
pen.DashStyle = DashStyle.Dash;
157
if (classtype.IsSealed)
162
if (classtype.IsStatic)
164
pen.DashStyle = DashStyle.Dash;
171
public override bool IsVResizable
173
get { return false; }
176
protected virtual DrawableRectangle InitContentBackground()
180
int radius = CornerRadius;
181
return new DrawableRectangle(ContentBG, null, 0, 0, radius, radius);
184
return new DrawableRectangle(ContentBG, null, 0, 0, 0, 0);
187
protected virtual DrawableItemsStack InitContentContainer(params IDrawableRectangle[] items)
189
DrawableItemsStack content = new DrawableItemsStack();
190
content.OrientationAxis = Axis.Z;
192
content.Add(InitContentBackground());
194
foreach (IDrawableRectangle item in items)
200
protected virtual IDrawableRectangle InitContent ()
202
groups.MinWidth = 80;
209
public void Initialize ()
211
PrepareMembersContent();
213
Width = GetAbsoluteContentWidth();
216
#region Graphics related members
218
static Color titlesBG = Color.FromArgb(255,217, 225, 241);
219
protected virtual Color TitleBackground
221
get { return titlesBG; }
224
protected virtual LinearGradientBrush TitleBG
229
static Brush innerTitlesBG = new SolidBrush(Color.FromArgb(255, 240, 242, 249));
230
protected virtual Brush InnerTitlesBackground
232
get { return innerTitlesBG; }
235
static Brush contentBG = new SolidBrush(Color.FromArgb(255, 255, 255, 255));
236
protected virtual Brush ContentBG
238
get { return contentBG; }
241
protected virtual bool RoundedCorners
246
protected virtual int CornerRadius
254
protected IAmbience GetAmbience()
256
IAmbience ambience = AmbienceService.GetCurrentAmbience();
257
ambience.ConversionFlags = ConversionFlags.None;
261
protected virtual void PrepareTitles ()
263
if (classtype == null) return;
265
IAmbience ambience = GetAmbience();
267
DrawableItemsStack title = new DrawableItemsStack();
268
title.OrientationAxis = Axis.X;
270
TextSegment titleString = new TextSegment(base.Graphics, classtype.Name, TitleFont, true);
271
title.Add(titleString);
272
title.Add(collapseExpandShape);
274
collapseExpandShape.Collapsed = Collapsed;
276
titles.OrientationAxis = Axis.Y;
280
titles.Add(new TextSegment(base.Graphics, typeclass, SubtextFont, true));
282
if (classtype.BaseClass != null)
284
DrawableItemsStack inherits = new DrawableItemsStack();
285
inherits.OrientationAxis = Axis.X;
286
inherits.Add(new InheritanceShape());
287
inherits.Add(new TextSegment(base.Graphics, classtype.BaseClass.Name, SubtextFont, true));
288
titles.Add(inherits);
291
foreach (IReturnType rt in classtype.BaseTypes)
293
IClass ct = rt.GetUnderlyingClass();
294
if (ct != null && ct.ClassType == ClassType.Interface)
295
interfaces.Add(new TextSegment(base.Graphics, ambience.Convert(rt), SubtextFont, true));
299
protected class MemberData : IComparable<MemberData>
301
public MemberData (IMember member, IAmbience ambience, Graphics graphics, Font font)
303
IMethod methodMember = member as IMethod;
304
IEvent eventMember = member as IEvent;
305
IProperty propertyMember = member as IProperty;
306
IField fieldMember = member as IField;
308
DrawableItemsStack<VectorShape> image = new DrawableItemsStack<VectorShape>();
309
image.OrientationAxis = Axis.Z; // stack image components one on top of the other
310
image.KeepAspectRatio = true;
312
if (methodMember != null)
314
memberString = ambience.Convert(methodMember) + " : " + ambience.Convert(member.ReturnType);
315
image.Add(new MethodShape());
317
else if (eventMember != null)
319
memberString = ambience.Convert(eventMember) + " : " + ambience.Convert(member.ReturnType);
320
image.Add(new EventShape());
322
else if (fieldMember != null)
324
memberString = ambience.Convert(fieldMember) + " : " + ambience.Convert(member.ReturnType);
325
image.Add(new FieldShape());
327
else if (propertyMember != null)
329
memberString = ambience.Convert(propertyMember) + " : " + ambience.Convert(member.ReturnType);
330
image.Add(new PropertyShape());
333
memberItem.OrientationAxis = Axis.X;
334
memberItem.Add(image);
335
memberItem.Add(new TextSegment(graphics, memberString, font, true));
340
InteractiveItemsStack memberItem = new InteractiveItemsStack(false);
344
public string MemberString
346
get { return memberString; }
349
public int CompareTo(MemberData other)
351
return memberString.CompareTo(other.MemberString);
354
public InteractiveItemsStack Item
356
get { return memberItem; }
360
protected InteractiveHeaderedItem PrepareGroup (string title, IDrawableRectangle content)
362
#region Prepare Group Container
363
DrawableItemsStack headerPlus = new DrawableItemsStack();
364
DrawableItemsStack headerMinus = new DrawableItemsStack();
366
headerPlus.OrientationAxis = Axis.X;
367
headerMinus.OrientationAxis = Axis.X;
370
#region Create Header
371
TextSegment titleSegment = new TextSegment(Graphics, title, GroupTitleFont, true);
373
PlusShape plus = new PlusShape();
375
headerPlus.Add(plus);
376
headerPlus.Add(titleSegment);
378
MinusShape minus = new MinusShape();
380
headerMinus.Add(minus);
381
headerMinus.Add(titleSegment);
383
DrawableItemsStack headerCollapsed = new DrawableItemsStack();
384
DrawableItemsStack headerExpanded = new DrawableItemsStack();
386
headerCollapsed.OrientationAxis = Axis.Z;
387
headerExpanded.OrientationAxis = Axis.Z;
389
headerCollapsed.Add (new DrawableRectangle(InnerTitlesBackground, null));
390
headerCollapsed.Add (headerPlus);
392
headerExpanded.Add (new DrawableRectangle(InnerTitlesBackground, null));
393
headerExpanded.Add (headerMinus);
396
InteractiveHeaderedItem tg = new InteractiveHeaderedItem(headerCollapsed, headerExpanded, content);
397
tg.HeaderClicked += delegate { tg.Collapsed = !tg.Collapsed; };
398
IMouseInteractable interactive = content as IMouseInteractable;
399
if (interactive != null)
400
tg.ContentClicked += delegate (object sender, PointF pos) { interactive.HandleMouseClick(pos); };
401
tg.RedrawNeeded += HandleRedraw;
406
protected virtual InteractiveItemsStack PrepareMembersContent <MT> (ICollection<MT> members) where MT : IMember
408
if (members == null) return null;
409
if (members.Count == 0) return null;
410
InteractiveItemsStack content = new InteractiveItemsStack();
411
content.OrientationAxis = Axis.Y;
412
PrepareMembersContent <MT> (members, content);
416
private InteractiveItemsStack PrepareNestedTypesContent()
418
InteractiveItemsStack innerItems = new InteractiveItemsStack();
419
innerItems.OrientationAxis = Axis.Y;
420
innerItems.Spacing = 10;
421
innerItems.Padding = 10;
422
foreach (IClass ct in classtype.InnerClasses)
424
ClassCanvasItem innerItem = ClassCanvas.CreateItemFromType(ct);
425
innerItems.Add(innerItem);
426
innerItem.LayoutChanged += HandleRedraw;
431
protected virtual void PrepareMembersContent <MT> (ICollection<MT> members, InteractiveItemsStack content) where MT : IMember
433
if (members == null) return;
434
if (members.Count == 0) return;
436
IAmbience ambience = GetAmbience();
438
#region Prepare Group Members
439
List<MemberData> membersData = new List<MemberData>();
440
foreach (MT member in members)
442
membersData.Add(new MemberData(member, ambience, Graphics, MemberFont));
447
#region Add Members To Group
448
foreach (MemberData memberData in membersData)
450
content.Add(memberData.Item);
455
private void AddGroupToContent(string title, InteractiveItemsStack groupContent)
457
if (groupContent != null)
459
InteractiveHeaderedItem tg = PrepareGroup (title, groupContent);
460
groupNames.Add(tg, title);
461
groupsByName.Add(title, tg);
466
protected virtual void PrepareMembersContent ()
468
if (classtype == null) return;
472
InteractiveItemsStack propertiesContent = PrepareMembersContent <IProperty> (classtype.Properties);
473
InteractiveItemsStack methodsContent = PrepareMembersContent <IMethod> (classtype.Methods);
474
InteractiveItemsStack fieldsContent = PrepareMembersContent <IField> (classtype.Fields);
475
InteractiveItemsStack eventsContent = PrepareMembersContent <IEvent> (classtype.Events);
477
AddGroupToContent("Properties", propertiesContent);
478
AddGroupToContent("Methods", methodsContent);
479
AddGroupToContent("Fields", fieldsContent);
480
AddGroupToContent("Events", eventsContent);
482
if (classtype.InnerClasses.Count > 0)
484
InteractiveItemsStack nestedTypesContent = PrepareNestedTypesContent();
485
AddGroupToContent("Nested Types", nestedTypesContent);
489
protected virtual void PrepareFrame ()
491
ActualHeight = classItemContainer.GetAbsoluteContentHeight();
493
if (Container != null) return;
495
shadowpath = new GraphicsPath();
498
int radius = CornerRadius;
499
shadowpath.AddArc(ActualWidth-radius + 4, 3, radius, radius, 300, 60);
500
shadowpath.AddArc(ActualWidth-radius + 4, ActualHeight - radius + 3, radius, radius, 0, 90);
501
shadowpath.AddArc(4, ActualHeight-radius + 3, radius, radius, 90, 45);
502
shadowpath.AddArc(ActualWidth-radius, ActualHeight - radius, radius, radius, 90, -90);
506
shadowpath.AddPolygon(new PointF[] {
507
new PointF(ActualWidth, 3),
508
new PointF(ActualWidth + 4, 3),
509
new PointF(ActualWidth + 4, ActualHeight + 3),
510
new PointF(4, ActualHeight + 3),
511
new PointF(4, ActualHeight),
512
new PointF(ActualWidth, ActualHeight)
515
shadowpath.CloseFigure();
520
public override void DrawToGraphics (Graphics graphics)
522
grad.ResetTransform();
523
grad.TranslateTransform(AbsoluteX, AbsoluteY);
524
grad.ScaleTransform(ActualWidth, 1);
526
GraphicsState state = graphics.Save();
527
graphics.TranslateTransform (AbsoluteX, AbsoluteY);
529
if (Container == null)
532
graphics.FillPath(CanvasItem.ShadowBrush, shadowpath);
535
classItemContainer.Width = Width;
536
classItemContainer.Height = Height;
538
graphics.Restore(state);
539
classItemContainer.DrawToGraphics(graphics);
541
//Draw interfaces lollipops
542
//TODO - should be converted to an headered item.
543
if (interfaces.Count > 0)
545
interfaces.X = AbsoluteX + 15;
546
interfaces.Y = AbsoluteY - interfaces.ActualHeight - 1;
547
interfaces.DrawToGraphics(graphics);
549
graphics.DrawEllipse(Pens.Black, AbsoluteX + 9, AbsoluteY - interfaces.ActualHeight - 11, 10, 10);
550
graphics.DrawLine(Pens.Black, AbsoluteX + 14, AbsoluteY - interfaces.ActualHeight - 1, AbsoluteX + 14, AbsoluteY);
553
base.DrawToGraphics(graphics);
556
public bool Collapsed
558
get { return classItemHeaderedContent.Collapsed; }
561
classItemHeaderedContent.Collapsed = value;
562
collapseExpandShape.Collapsed = value;
568
private void HandleRedraw (object sender, EventArgs args)
576
public override void HandleMouseClick (PointF pos)
578
base.HandleMouseClick(pos);
580
if (collapseExpandShape.IsInside(pos.X, pos.Y))
582
Collapsed = !Collapsed;
586
foreach (InteractiveHeaderedItem tg in groups)
590
tg.HandleMouseClick(pos);
600
protected override XmlElement CreateXmlElement(XmlDocument doc)
602
return doc.CreateElement("Class");
605
protected override void FillXmlElement(XmlElement element, XmlDocument document)
607
base.FillXmlElement(element, document);
608
element.SetAttribute("Name", RepresentedClassType.FullyQualifiedName);
609
element.SetAttribute("Collapsed", Collapsed.ToString());
612
XmlElement compartments = document.CreateElement("Compartments");
613
foreach (InteractiveHeaderedItem tg in groups)
615
XmlElement grp = document.CreateElement("Compartment");
616
grp.SetAttribute("Name", groupNames[tg]);
617
grp.SetAttribute("Collapsed", tg.Collapsed.ToString());
618
compartments.AppendChild(grp);
620
element.AppendChild(compartments);
624
public override void LoadFromXml (XPathNavigator navigator)
626
base.LoadFromXml(navigator);
628
Collapsed = bool.Parse(navigator.GetAttribute("Collapsed", ""));
630
XPathNodeIterator compNI = navigator.Select("Compartments/Compartment");
631
while (compNI.MoveNext())
633
XPathNavigator compNav = compNI.Current;
634
InteractiveHeaderedItem grp;
635
if (groupsByName.TryGetValue(compNav.GetAttribute("Name", ""), out grp))
637
grp.Collapsed = bool.Parse(compNav.GetAttribute("Collapsed", ""));
644
public void Dispose()
647
if (shadowpath != null)
648
shadowpath.Dispose();
651
public override string ToString()
653
return "ClasCanvasItem: " + classtype.Name;