public void TestMainMenuReading008() { String content = ReadResource(Resources.MainMenu_008); IBDocument document = IBDocument.LoadFromXml(content); CheckDocument(document); }
public void TestMyDocumentReading005() { String content = ReadResource(Resources.MyDocument_005); IBDocument document = IBDocument.LoadFromXml(content); CheckDocument(document); }
public override CodeCompileUnit Generate(ProjectFile xibFile, CodeDomProvider provider, CodeGeneratorOptions options) { var doc = XDocument.Load(xibFile.FilePath); var ibDoc = IBDocument.Deserialize(doc); var project = (DotNetProject)xibFile.Project; var ccu = new CodeCompileUnit(); var ns = new CodeNamespace(project.GetDefaultNamespace(xibFile.FilePath)); ccu.Namespaces.Add(ns); foreach (var ctd in GetTypes(ibDoc, provider, options)) { ns.Types.Add(ctd); } return(ccu); }
public void TestMainMenuReading012() { String content = ReadResource(Resources.MainMenu_012); IBDocument document = IBDocument.LoadFromXml(content); CheckDocument(document); ClassDescriptionCollector collector = new ClassDescriptionCollector(); document.Root.Accept(collector); Assert.AreEqual(3, collector.ClassNames.Count()); Assert.IsTrue(collector.ClassNames.Contains("MainController")); IEnumerable <IBPartialClassDescription> classDescriptions = collector["MainController"]; IEnumerable <IBOutletDescriptor> outlets = classDescriptions.SelectMany(d => d.Outlets); IEnumerable <IBActionDescriptor> actions = classDescriptions.SelectMany(d => d.Actions); Assert.AreEqual(3, outlets.Count()); Assert.AreEqual(2, actions.Count()); }
IEnumerable <CodeTypeDeclaration> GetTypes(IBDocument doc, CodeDomProvider provider, CodeGeneratorOptions options) { object outVar; UnknownIBObject objects; if (!doc.Properties.TryGetValue("IBDocument.Objects", out outVar) || (objects = outVar as UnknownIBObject) == null) { return(new CodeTypeDeclaration[0]); } //process the connection records NSMutableArray connectionRecords; if (!objects.Properties.TryGetValue("connectionRecords", out outVar) || (connectionRecords = outVar as NSMutableArray) == null) { return(new CodeTypeDeclaration[0]); } //group connection records by type ref ID var typeRecords = new Dictionary <int, List <IBConnectionRecord> > (); foreach (var record in connectionRecords.Values.OfType <IBConnectionRecord> ()) { //get the type this member belongs in var ev = record.Connection as IBActionConnection; var outlet = record.Connection as IBOutletConnection; if (outlet == null && ev == null) { //not a recognised connection type. probably a desktop xib continue; } int?typeIndex = ((IBObject)(ev != null ? ev.Destination.Reference : outlet.Source.Reference)).Id; if (typeIndex == null) { throw new InvalidOperationException("Connection " + record.ConnectionId + " references null object ID"); } List <IBConnectionRecord> records; if (!typeRecords.TryGetValue(typeIndex.Value, out records)) { typeRecords[typeIndex.Value] = records = new List <IBConnectionRecord> (); } records.Add(record); } //grab the custom class names, keyed by object ID var classNames = new Dictionary <int, string> (); var flattenedProperties = (NSMutableDictionary)objects.Properties ["flattenedProperties"]; foreach (var pair in flattenedProperties.Values) { string keyStr = (string)pair.Key; if (!keyStr.EndsWith(".CustomClassName")) { continue; } int key = int.Parse(keyStr.Substring(0, keyStr.IndexOf('.'))); string name = (string)pair.Value; //HACK: why does IB not generate partial classes for UIApplication or UIResponder? I guess we should suppress them too if (name == "UIApplication" || name == "UIResponder") { continue; } classNames[key] = (string)pair.Value; } // it seems to be hard to figure out which objects we should generate classes for, // so take the list of classes that xcode would generate var ibApprovedPartialClassNames = new HashSet <string> (); UnknownIBObject classDescriber; if (doc.Properties.TryGetValue("IBDocument.Classes", out outVar) && (classDescriber = outVar as UnknownIBObject) != null) { NSMutableArray arr; if (classDescriber.Properties.TryGetValue("referencedPartialClassDescriptions", out outVar) && (arr = outVar as NSMutableArray) != null) { foreach (var cls in arr.Values.OfType <IBPartialClassDescription> ()) { if (!String.IsNullOrEmpty(cls.ClassName)) { ibApprovedPartialClassNames.Add(cls.ClassName); } } } } // construct the type objects, keyed by ref ID var objectRecords = (IBMutableOrderedSet)objects.Properties ["objectRecords"]; var customTypeNames = new Dictionary <int, string> (); var types = new Dictionary <int, CodeTypeDeclaration> (); foreach (IBObjectRecord record in objectRecords.OrderedObjects.OfType <IBObjectRecord> ()) { string name; int? objId = ((IBObject)ResolveIfReference(record.Object)).Id; if (objId != null && classNames.TryGetValue(record.ObjectId, out name)) { customTypeNames[objId.Value] = name; if (!ibApprovedPartialClassNames.Contains(name)) { continue; } //HACK to avoid duplicate class definitions, which is not compilable ibApprovedPartialClassNames.Remove(name); var type = new CodeTypeDeclaration(name) { IsPartial = true }; type.CustomAttributes.Add( new CodeAttributeDeclaration("MonoTouch.Foundation.Register", new CodeAttributeArgument(new CodePrimitiveExpression(name)))); //FIXME: implement proper base class resolution. I'm not sure where the info is - it might need some // inference rules var obj = ResolveIfReference(record.Object); if (obj != null) { string baseType = "MonoTouch.Foundation.NSObject"; if (obj is IBProxyObject) { baseType = "MonoTouch.UIKit.UIViewController"; } else if (obj is UnknownIBObject) { var uobj = (UnknownIBObject)obj; //if the item comes from another nib, don't generate the partial class in this xib's codebehind if (uobj.Properties.ContainsKey("IBUINibName") && !String.IsNullOrEmpty(uobj.Properties["IBUINibName"] as string)) { continue; } baseType = GetTypeName(null, uobj) ?? "MonoTouch.Foundation.NSObject"; } type.Comments.Add(new CodeCommentStatement(String.Format("Base type probably should be {0} or subclass", baseType))); } types.Add(objId.Value, type); } } foreach (KeyValuePair <int, List <IBConnectionRecord> > typeRecord in typeRecords) { CodeTypeDeclaration type; if (!types.TryGetValue(typeRecord.Key, out type)) { continue; } //separate out the actions and outlets var actions = new List <IBActionConnection> (); var outlets = new List <IBOutletConnection> (); foreach (var record in typeRecord.Value) { if (record.Connection is IBActionConnection) { actions.Add((IBActionConnection)record.Connection); } else if (record.Connection is IBOutletConnection) { outlets.Add((IBOutletConnection)record.Connection); } } //process the actions, grouping ones with the same name foreach (var actionGroup in actions.GroupBy(a => a.Label)) { //find a common sender type for all the items in the grouping CodeTypeReference senderType = null; foreach (IBActionConnection ev in actionGroup) { var sender = ResolveIfReference(ev.Source) as IBObject; var newType = new CodeTypeReference(GetTypeName(customTypeNames, sender) ?? "MonoTouch.Foundation.NSObject"); if (senderType == null) { senderType = newType; continue; } else if (senderType == newType) { continue; } else { //FIXME: resolve common type newType = new CodeTypeReference("MonoTouch.Foundation.NSObject"); break; } } if (type.Members.Count == 0) { AddWarningDisablePragmas(type, provider); } //create the action method and add it StringWriter actionStubWriter = null; GenerateAction(type, actionGroup.Key, senderType, provider, options, ref actionStubWriter); if (actionStubWriter != null) { type.Comments.Add(new CodeCommentStatement(actionStubWriter.ToString())); actionStubWriter.Dispose(); } } foreach (var outlet in outlets) { CodeTypeReference outletType; //destination is widget, so get type var widget = ResolveIfReference(outlet.Destination.Reference) as IBObject; outletType = new CodeTypeReference(GetTypeName(customTypeNames, widget) ?? "System.Object"); if (type.Members.Count == 0) { AddWarningDisablePragmas(type, provider); } AddOutletProperty(type, outlet.Label, outletType); } } return(types.Values); }
public override CodeCompileUnit Generate(ProjectFile xibFile, CodeDomProvider provider, CodeGeneratorOptions options) { var xibDoc = XDocument.Load(xibFile.FilePath); var ibDoc = IBDocument.Deserialize(xibDoc); var ccu = new CodeCompileUnit(); object outVar; UnknownIBObject classDescriber; if (!ibDoc.Properties.TryGetValue("IBDocument.Classes", out outVar) || (classDescriber = outVar as UnknownIBObject) == null) { return(ccu); } NSMutableArray arr; if (!classDescriber.Properties.TryGetValue("referencedPartialClassDescriptions", out outVar) || (arr = outVar as NSMutableArray) == null) { return(ccu); } var project = (DotNetProject)xibFile.Project; var defaultNS = project.GetDefaultNamespace(xibFile.FilePath); var nsDict = new Dictionary <string, CodeNamespace> (); foreach (var cls in arr.Values.OfType <IBPartialClassDescription> ()) { if (string.IsNullOrEmpty(cls.ClassName)) { continue; } var si = cls.SourceIdentifier.Value; if (si == null || si.MajorKey != "IBUserSource") { continue; } var type = new CodeTypeDeclaration(cls.ClassName) { IsPartial = true, }; type.CustomAttributes.Add( new CodeAttributeDeclaration("MonoMac.Foundation.Register", new CodeAttributeArgument(new CodePrimitiveExpression(cls.ClassName)))); var sc = GetTypeReference(cls.SuperclassName ?? "id"); type.Comments.Add(new CodeCommentStatement("Should subclass " + sc.BaseType)); //type.BaseTypes.Add (sc); if (cls.Actions != null) { foreach (var action in cls.Actions.Values) { AddWarningDisablePragmas(type, provider); StringWriter actionStubWriter = null; var sender = GetTypeReference((string)action.Value); GenerateAction(type, (string)action.Key, sender, provider, options, ref actionStubWriter); if (actionStubWriter != null) { type.Comments.Add(new CodeCommentStatement(actionStubWriter.ToString())); actionStubWriter.Dispose(); } } } if (cls.Outlets != null) { foreach (var outlet in cls.Outlets.Values) { AddWarningDisablePragmas(type, provider); AddOutletProperty(type, (string)outlet.Key, GetTypeReference((string)outlet.Value)); } } //FIXME: use _ as namespace separator var ns = defaultNS; CodeNamespace cn; if (!nsDict.TryGetValue(ns, out cn)) { cn = new CodeNamespace(ns); nsDict.Add(ns, cn); ccu.Namespaces.Add(cn); } cn.Types.Add(type); } return(ccu); }
private static void CheckDocument(IBDocument document) { Assert.IsNotNull(document.Root); }