/// <summary> /// Get (or try to get) the first and the best protocol that implements the given message. /// </summary> /// <param name="methodName">Selector of the message to look for.</param> /// <param name="methodType">Type of the method (instance / class) to look for.</param> /// <param name="cls">Class where to start looking for the method.</param> /// <param name="protocolName">Optional protocol that may contain the message.</param> /// <returns>Message definition for the given selector or null if one was not found.</returns> public static Definitions.Description.Message GetMessageForMethod(string methodName, MethodType methodType, Class cls, string protocolName) { if (String.IsNullOrWhiteSpace(methodName)) { throw new ArgumentNullException("methodName"); } if (methodType == null) { throw new ArgumentNullException("methodType"); } if (cls == null) { throw new ArgumentNullException("cls"); } while (cls != null) { Definitions.Description.Message msg = null; var prot = cls.Parent.SmalltalkSystem.SystemDescription.Protocols.FirstOrDefault(p => p.Name == protocolName); if (prot != null) { msg = prot.Messages.FirstOrDefault(m => m.Selector == methodName); } if (msg != null) { return(msg); } List <Class> classesList; List <Class> superclassesList; Dictionary <string, Class> classesMap; Dictionary <string, List <Class> > protocolNameClassesMap; Dictionary <string, List <Class> > protocolNameSuperslassesMap; Dictionary <string, List <Class> > methodNameClassesMap; Dictionary <string, List <Class> > methodNameSuperclassesMap; Dictionary <string, List <string> > methodNameProtocolNamesMap; Dictionary <string, List <string> > allMethodNameProtocolNamesMap; Dictionary <string, Definitions.Description.Protocol> protocolMap; HashSet <string> subclassResponsibilityMethods; Dictionary <string, List <Class> > methodNameLocalImplementorsMap; Dictionary <string, List <Class> > methodNameSuperImplementorsMap; MethodHelper.BuildLists(cls, cls, methodType, out classesList, out superclassesList, out classesMap, out protocolNameClassesMap, out protocolNameSuperslassesMap, out methodNameClassesMap, out methodNameSuperclassesMap, out methodNameProtocolNamesMap, out allMethodNameProtocolNamesMap, out protocolMap, out subclassResponsibilityMethods, out methodNameLocalImplementorsMap, out methodNameSuperImplementorsMap); List <string> pns; methodNameProtocolNamesMap.TryGetValue(methodName, out pns); if ((pns != null) && (pns.Count > 0)) { protocolMap.TryGetValue(pns[0], out prot); if (prot != null) { msg = prot.Messages.FirstOrDefault(m => m.Selector == methodName); } } if (msg != null) { return(msg); } if (String.IsNullOrWhiteSpace(cls.SuperclassName)) { cls = null; } else { cls = cls.Parent.Classes.FirstOrDefault(c => c.Name == cls.SuperclassName); } } return(null); }
private void FillView() { if (this.ListItemChanging) { return; } this.Enabled = false; this.listMethods.Items.Clear(); if (this.Class == null) { return; } if (String.IsNullOrWhiteSpace(this.ProtocolName)) { return; } if (this.MethodType == null) { return; } this.listMethods.BeginUpdate(); Font normalFont = this.listMethods.Font; Font boldFont = new Font(normalFont, FontStyle.Bold); List <Class> classesList; List <Class> superclassesList; Dictionary <string, Class> classesMap; Dictionary <string, List <Class> > protocolNameClassesMap; Dictionary <string, List <Class> > protocolNameSuperslassesMap; Dictionary <string, List <Class> > methodNameClassesMap; Dictionary <string, List <Class> > methodNameSuperclassesMap; Dictionary <string, List <string> > methodNameProtocolNamesMap; Dictionary <string, List <string> > allMethodNameProtocolNamesMap; Dictionary <string, Definitions.Description.Protocol> protocolMap; HashSet <string> subclassResponsibilityMethods; Dictionary <string, List <Class> > methodNameLocalImplementorsMap; Dictionary <string, List <Class> > methodNameSuperImplementorsMap; MethodHelper.BuildLists(this.Class, this.IncludeUpToClass, this.MethodType, out classesList, out superclassesList, out classesMap, out protocolNameClassesMap, out protocolNameSuperslassesMap, out methodNameClassesMap, out methodNameSuperclassesMap, out methodNameProtocolNamesMap, out allMethodNameProtocolNamesMap, out protocolMap, out subclassResponsibilityMethods, out methodNameLocalImplementorsMap, out methodNameSuperImplementorsMap); /* *** CREATE THE LIST OF METHODS *** * The logic is as follows: * 1. Consider methods that: * a. Are implemented by the this.Class itself * b. Are implemented by any superclass up to and incl. this.IncludeUpToClass * c. Are defined (actually messages) in any protocol that this.Class wants to implement * d. Are defined (actually messages) in any protocol that any superclass up to and incl. this.IncludeUpToClass wants to implement * * Obviously, depending on this.MethodType we concider only the class methods/protocols or the instance ones * 2. Filter methods so: * a. If this.ProtocolName is "ANY", then include everything. * b. If this.ProtocolName is "PRIVATE", then include method found in 1.a. or 1.b. but NOT also in 1.c. and 1.d. * c. Include methods found in 1.c. or 1.d. according to the name of the selected protocol * d. Similar to b., but also method in any protocol that any of the superclasses wants to implements * * 3. Create list items for each method with following details: * a. Method selector * b. Lists if protocols defining it (similar to 1.c and 1.d but up to the root class) * c. Local implementors of the methods (subclasses of this.Class, but NOT this.Class itself) * d. Super implementors of the methods (superclasses of this.IncludeUpToClass, but NOT this.IncludeUpToClass itself) * 4. Decorate (color) each item: * a. Only defined (in protocols) but not implemented: Gray * b. Implementation is empty and super implementor exists that says subclassResponsibility: Red * c. Found in 1.a. or 1.c. (as oposite to 1.b and 1.d): Bold Font */ HashSet <string> methodNames = new HashSet <string>(); methodNames.UnionWith(methodNameClassesMap.Keys); methodNames.UnionWith(methodNameProtocolNamesMap.Keys); foreach (string selector in methodNames.OrderBy(s => s)) { bool include; if (this.ProtocolName == "ANY") { include = true; } else if (this.ProtocolName == "PRIVATE") { include = !methodNameProtocolNamesMap.ContainsKey(selector) || (methodNameProtocolNamesMap[selector].Count == 0); } else { include = allMethodNameProtocolNamesMap.ContainsKey(selector) && allMethodNameProtocolNamesMap[selector].Contains(this.ProtocolName); } if (include) { ListViewItem lvi = this.listMethods.Items.Add(selector, "method"); lvi.Tag = selector; lvi.UseItemStyleForSubItems = false; // Is the method implemented by any class (as oposite by only defined by a protocol implemented by the class) if (!methodNameClassesMap.ContainsKey(selector)) { lvi.ForeColor = Color.Gray; } // Is this a method that we must override? if (subclassResponsibilityMethods.Contains(selector)) { lvi.ForeColor = Color.Red; } IEnumerable <string> definingProtocols = new string[0]; if (allMethodNameProtocolNamesMap.ContainsKey(selector)) { definingProtocols = allMethodNameProtocolNamesMap[selector]; } // This is a method defined in locally implemented protocol if (definingProtocols.Any(pn => protocolNameClassesMap.ContainsKey(pn) && protocolNameClassesMap[pn].Contains(this.Class))) { lvi.Font = boldFont; } // This is a locally implemented method if (methodNameClassesMap.ContainsKey(selector) && methodNameClassesMap[selector].Contains(this.Class)) { lvi.Font = boldFont; } IEnumerable <Class> implementingClasses = new Class[0]; if (methodNameClassesMap.ContainsKey(selector)) { implementingClasses = methodNameClassesMap[selector]; } // Protocols: (which protocols defines the method) string protocols = String.Join(", ", definingProtocols.OrderBy(p => p)); lvi.SubItems.Add((String.IsNullOrWhiteSpace(protocols) ? "PRIVATE" : protocols)); lvi.SubItems[lvi.SubItems.Count - 1].Font = lvi.Font; lvi.SubItems[lvi.SubItems.Count - 1].ForeColor = lvi.ForeColor; // Local Implementors: (excluding the current class) lvi.SubItems.Add(String.Join(", ", methodNameLocalImplementorsMap[selector].Select(c => c.Name))).Font = normalFont; // Super Implementors: (excluding listed classes) lvi.SubItems.Add(String.Join(", ", methodNameSuperImplementorsMap[selector].Select(c => c.Name))).Font = normalFont; lvi.ToolTipText = String.Format("Defined: {0}\nImplemented: {1}", protocols, String.Join(", ", implementingClasses.Select(c => c.Name))); lvi.Selected = (this.MethodName == selector); } } this.listMethods.EndUpdate(); if (this.listMethods.SelectedItems.Count > 0) { this.listMethods.SelectedItems[0].EnsureVisible(); } this.Enabled = true; }