Added real parser integration, removing prototype designer types

This commit is contained in:
7sharp9 2014-07-08 18:44:44 +01:00
Родитель 2bd78d53a5
Коммит b8b692d1c6
5 изменённых файлов: 92 добавлений и 185 удалений

Просмотреть файл

@ -1,45 +0,0 @@
namespace Xamarin.iOSProviders
open System
open System.Xml
open System.Xml.Linq
open System.Linq
[<AutoOpenAttribute>]
module Xml =
let inline xn name = XName.op_Implicit(name)
type IosAction =
{selector:string; destination:string; eventType:string; id:string}
static member Parse(action: XElement) =
{selector = action.Attribute(xn "selector").Value
destination = action.Attribute(xn "destination").Value
eventType = action.Attribute(xn "eventType").Value
id = action.Attribute(xn "id").Value }
type Outlet =
{Name:string;Type:Type;Xml:string}
static member Parse(outlet:XElement) =
let name = outlet.Attribute(xn "property").Value
let destination = outlet.Attribute(xn "destination").Value
let destinationElement =
let viewcontroller = outlet.Parent.Parent
let view = outlet.Parent.Parent.Descendants(xn "view") |> Seq.toArray
let subviews = view.Descendants(xn "subviews") |> Seq.toArray
subviews.Descendants()
|> Seq.tryFind (fun xx -> let id = xx.Attribute(xn "id")
if id = null then false
else id.Value = destination)
match destinationElement with
| Some element ->
match TypeSystem.typeMap.TryFind element.Name.LocalName with
| Some typ -> {Name=name;Type=typ;Xml= outlet.ToString()}
| None -> failwithf "Unknown Outlet type: %s" element.Name.LocalName
| None -> failwithf "Could not find outlet destination: %s" destination
type ViewController =
{id:string; customClass:string; sceneMemberID:string}
static member Parse(vc: XElement) =
{id = vc.Attribute(xn "id").Value
customClass = vc.Attribute(xn "customClass").Value
sceneMemberID = vc.Attribute(xn "sceneMemberID").Value}

Просмотреть файл

@ -0,0 +1,45 @@
#load "ProvidedTypes.fs"
#load "TypeSystem.fs"
#I "bin/Debug"
#r "monotouch.dll"
#r "System.xml"
#r "System.Xml.Linq"
#r "FSharp.Compatibility.OCaml"
#r "MonoTouch.Design"
open System
open System.IO
open System.Reflection
open System.Linq
open System.Xml.Linq
open System.Collections.Generic
open System.Reflection
open ProviderImplementation.ProvidedTypes
open Microsoft.FSharp.Core.CompilerServices
open Microsoft.FSharp.Quotations
open MonoTouch.Design
open MonoTouch.Foundation
open MonoTouch.UIKit
open ProviderImplementation.ProvidedTypes
let storyboardName = "/Users/dave/code/xamarin/fsharp-iOS-designer/src/ReferenceApps/CS_ViewController/garbage.storyboard"
let stream = File.OpenRead (storyboardName)
let xdoc = XDocument.Load(stream)
let parsed = Parser.Instance.Parse(xdoc.Root)
let storyboard =
match parsed with
| :? Storyboard as sb ->
sb
//| :? Xib as xib ->
//TODO
| _ -> failwith "broken"
let sc = storyboard.Scenes.[0]
let vc = sc.ViewController
let outlet = vc.Outlets.[0]
let iuthing = storyboard.FindById(outlet.Destination) :?> ProxiedUiKitObject
iuthing.DisplayClassName
outlet

Просмотреть файл

@ -1,107 +0,0 @@
namespace Xamarin.iOSProviders
open System
open System.Drawing
open MonoTouch
open MonoTouch.UIKit
open MonoTouch.Foundation
open MonoTouch.Design
type StaticHelpers() =
static member InstantiateInitialViewController<'a when 'a :> NSObject>( storyboardName) =
let mainStoryboard = UIStoryboard.FromName (storyboardName, null)
let sb = mainStoryboard.InstantiateInitialViewController ()
let theType = sb.GetType()
sb :?> 'a
module TypeSystem =
let typeMap =
//TODO replace this with a call to xml to objc type and then look in the monotouch assembly for a type with a register attribute that matches the objc name
Map.ofList
[("activityIndicatorView", typeof<UIActivityIndicatorView>)
("adBannerView", typeof<MonoTouch.iAd.ADBannerView>)
("attributedString", typeof<NSMutableAttributedString>)
("autoresizingMask", typeof<UIViewAutoresizing>)
("barButtonItem", typeof<UIBarButtonItem>)
("button", typeof<UIButton>)
("color", typeof<UIColor>)
("collectionReusableView", typeof<UICollectionReusableView>)
("collectionView", typeof<UICollectionView>)
("collectionViewCell", typeof<UICollectionViewCell>)
("collectionViewController", typeof<UICollectionViewController>)
("collectionViewLayout", typeof<UICollectionViewLayout>)
("collectionViewFlowLayout", typeof<UICollectionViewFlowLayout>)
("constraint", typeof<NSLayoutConstraint>)
("containerView", typeof<UIView>)
("control", typeof<UIControl>)
("customObject", typeof<NSObject>)
("dataDetectorType", typeof<UIDataDetectorType>)
("date", typeof<MonoTouch.Foundation.NSDate>)
("datePicker", typeof<UIDatePicker>)
("dependencies", typeof<Dependencies>)
("deployment", typeof<Deployment>)
("development", typeof<Development>)
("extendedEdge", typeof<UIRectEdge>)
("font", typeof<UIFont>)
("fontDescription", typeof<UIFont>)
("glkView", typeof<GLKit.GLKView>)
("glkViewController", typeof<GLKit.GLKViewController>)
("imageView", typeof<UIImageView>)
("inset", typeof<UIEdgeInsets>)
("integer", typeof<int>)
("label", typeof<UILabel>)
("locale", typeof<MonoTouch.Foundation.NSLocale>)
("mapView", typeof<MapKit.MKMapView>)
("mutableData", typeof<MonoTouch.Foundation.NSData>)
("mutableString", typeof<string>)
("navigationBar", typeof<UINavigationBar>)
("navigationController", typeof<UINavigationController>)
("navigationItem", typeof<UINavigationItem>)
("offsetWrapper", typeof<UIOffset>)
("pageControl", typeof<UIPageControl>)
("panGestureRecognizer", typeof<UIPanGestureRecognizer>)
("paragraphStyle", typeof<NSMutableParagraphStyle>)
("pickerView", typeof<UIPickerView>)
("pinchGestureRecognizer", typeof<UIPinchGestureRecognizer>)
("plugIn", typeof<Plugin>)
("pageViewController", typeof<UIPageViewController>)
("progressView", typeof<UIProgressView>)
("point", typeof<PointF>)
("pongPressGestureRecognizer", typeof<UILongPressGestureRecognizer>) // the class name is an Xcode typo that we emulate
("real", typeof<float>)
("rect", typeof<RectangleF>)
("rotationGestureRecognizer", typeof<UIRotationGestureRecognizer>)
("scrollView", typeof<UIScrollView>)
("searchBar", typeof<UISearchBar>)
("searchDisplayController", typeof<UISearchDisplayController>)
("segmentedControl", typeof<UISegmentedControl>)
("size", typeof<SizeF>)
("slider", typeof<UISlider>)
("splitViewController", typeof<UISplitViewController>)
("splitViewDetailSimulatedSizeMetrics", typeof<SimulatedSplitViewDetailSizeMetrics>)
("splitViewMasterSimulatedSizeMetrics", typeof<SimulatedSplitViewMasterSizeMetrics>)
("state", typeof<Void>) //not needed client side//
("stepper", typeof<UIStepper>)
("string", typeof<string>)
("swipeGestureRecognizer", typeof<UISwipeGestureRecognizer>)
("switch", typeof<UISwitch>)
("tabBar", typeof<UITabBar>)
("tabBarController", typeof<UITabBarController>)
("tabBarItem", typeof<UITabBarItem>)
("tableView", typeof<UITableView>)
("tableViewCell", typeof<UITableViewCell>)
("tableViewController", typeof<UITableViewController>)
("tableViewSection", typeof<ProxiedTableViewSection>)
("tapGestureRecognizer", typeof<UITapGestureRecognizer>)
("textAttributes", typeof<UITextAttributes>)
("textField", typeof<UITextField>)
("toolbarItems", typeof<ToolbarItems>)
("textView", typeof<UITextView>)
("timeZone", typeof<MonoTouch.Foundation.NSTimeZone>)
("toolbar", typeof<UIToolbar>)
("view", typeof<UIView>)
("viewController", typeof<UIViewController>)
("viewControllerLayoutGuide", typeof<IUILayoutSupport>)
("window", typeof<UIWindow>)
("webView", typeof<UIWebView>) ]

Просмотреть файл

@ -77,14 +77,13 @@
<Reference Include="MonoTouch.Design.Client">
<HintPath>\Applications\Xamarin Studio.app\Contents\MacOS\lib\monodevelop\AddIns\MonoDevelop.IPhone\MonoTouch.Design.Client.dll</HintPath>
</Reference>
<Reference Include="System.Drawing" />
</ItemGroup>
<ItemGroup>
<Compile Include="AssemblyInfo.fs" />
<Compile Include="ProvidedTypes.fsi" />
<Compile Include="ProvidedTypes.fs" />
<Compile Include="ProvidedTypesHelpers.fs" />
<Compile Include="TypeSystem.fs" />
<Compile Include="DesignTimeTypes.fs" />
<Compile Include="Observable.fs" />
<Compile Include="IO.fs" />
<Compile Include="Debug.fs" />
@ -94,5 +93,6 @@
<ItemGroup>
<None Include="packages.config" />
<None Include="Script.fsx" />
<None Include="ParserIntegration.fsx" />
</ItemGroup>
</Project>

Просмотреть файл

@ -14,6 +14,7 @@ open MonoTouch.Foundation
open MonoTouch.UIKit
open Microsoft.FSharp.Compatibility.OCaml
open iOSDesignerTypeProvider.ProvidedTypes
open MonoTouch.Design
module Sanitise =
let cleanTrailing = String.trimEnd [|':'|]
@ -44,25 +45,31 @@ module Attributes =
module TypeBuilder =
let buildTypes (designerFile:Uri) (viewControllerElement: XElement) isAbstract addUnitCtor register =
let actions =
viewControllerElement.Descendants(Xml.xn "action")
|> Seq.map IosAction.Parse
let outlets =
viewControllerElement.Descendants(Xml.xn "outlet")
|> Seq.map Outlet.Parse |> Seq.toArray
let typeMap (proxy:ProxiedUiKitObject) =
//TODO: Expand this to also search in user assemblies
let monotouchAssembly = typeof<UIButton>.Assembly
query { for typ in monotouchAssembly.ExportedTypes do
where (query {for ca in typ.CustomAttributes do
exists (ca.AttributeType = typeof<RegisterAttribute> &&
match ca.ConstructorArguments |> Seq.map (fun ca -> ca.Value) |> Seq.toList with
| [:? string as name; :? bool as isWrapper] -> name = proxy.ClassName
| _ -> false)})
select typ
exactlyOne }
let viewController = ViewController.Parse(viewControllerElement)
// Generate the required type
let controllerType =
TypeSystem.typeMap
|> Map.filter (fun k v -> k.EndsWith("Controller"))
|> Map.tryFind viewController.sceneMemberID
|> function Some(t) -> t | _ -> failwith "No valid type found"
let buildTypes (designerFile:Uri) (vc: ProxiedViewController) isAbstract addUnitCtor register (config:TypeProviderConfig) =
let actions =
match vc.View with
| null -> Seq.empty
| view ->
match view.Subviews with
| null -> Seq.empty
| subviews -> subviews |> Seq.map (fun sv -> sv.Actions) |> Seq.concat
let providedController = ProvidedTypeDefinition(viewController.customClass + "Base", Some controllerType, IsErased=false )
let controllerType = typeMap vc
let providedController = ProvidedTypeDefinition(vc.CustomClass + "Base", Some controllerType, IsErased=false )
providedController.SetAttributes (if isAbstract then TypeAttributes.Public ||| TypeAttributes.Class ||| TypeAttributes.Abstract
else TypeAttributes.Public ||| TypeAttributes.Class)
@ -83,27 +90,27 @@ module TypeBuilder =
providedController.AddMember(emptyctor)
if register then
let register = Attributes.MakeRegisterAttributeData viewController.customClass
let register = Attributes.MakeRegisterAttributeData vc.CustomClass
providedController.AddCustomAttribute(register)
providedController.AddMember <| ProvidedLiteralField("CustomClass", typeof<string>, viewController.customClass)
providedController.AddMember <| ProvidedLiteralField("CustomClass", typeof<string>, vc.CustomClass)
//actions mutable assignment style----------------------------
//TODO add option for ObservableSource<NSObject>, potentially unneeded as outlets exposes this with observable...
for action in actions do
//create a backing field fand property or the action
let actionField, actionProperty = ProvidedTypes.ProvidedPropertyWithField(Sanitise.makeFieldName action.selector,
Sanitise.makeMethodName action.selector,
let actionField, actionProperty = ProvidedTypes.ProvidedPropertyWithField(Sanitise.makeFieldName action.Selector,
Sanitise.makeMethodName action.Selector,
typeof<Action<NSObject>>)
let actionBinding =
ProvidedMethod(methodName=Sanitise.makeSelectorMethodName action.selector,
ProvidedMethod(methodName=Sanitise.makeSelectorMethodName action.Selector,
parameters=[ProvidedParameter("sender", typeof<NSObject>)],
returnType=typeof<Void>,
InvokeCode = fun args -> let instance = Expr.Cast<Action<NSObject>>(Expr.FieldGet(args.[0], actionField))
<@@ if %instance <> null then (%instance).Invoke(%%args.[1]) @@>)
actionBinding.AddCustomAttribute(Attributes.MakeActionAttributeData(action.selector))
actionBinding.AddCustomAttribute(Attributes.MakeActionAttributeData(action.Selector))
actionBinding.SetMethodAttrs MethodAttributes.Private
providedController.AddMember actionField
@ -120,11 +127,13 @@ module TypeBuilder =
//outlets-----------------------------------------
let providedOutlets =
outlets
vc.Outlets
|> Array.map (fun outlet ->
let outletField, outletProperty = ProvidedTypes.ProvidedPropertyWithField(Sanitise.makeFieldName outlet.Name,
Sanitise.makePropertyName outlet.Name,
outlet.Type)
//type lookup here
let uiProxy = vc.Storyboard.FindById(outlet.Destination) :?> ProxiedUiKitObject
let outletField, outletProperty = ProvidedTypes.ProvidedPropertyWithField(Sanitise.makeFieldName outlet.Property,
Sanitise.makePropertyName outlet.Property,
typeMap uiProxy)
outletProperty.AddCustomAttribute <| Attributes.MakeOutletAttributeData()
///takes an instance returns a disposal expresion
@ -215,12 +224,17 @@ type iOSDesignerProvider(config: TypeProviderConfig) as this =
//generate storyboard container
let container = ProvidedTypeDefinition(asm, ns, typeName, Some(typeof<obj>), IsErased=false)
//TODO try to use MonoTouch.Design parsing, extract the models action/outlets etc
//let parsed = MonoTouch.Design.ClientParser.Instance.Parse(xdoc.Root)
let viewControllerElements = xdoc.Descendants(Xml.xn "viewController")
let scenes =
match Parser.Instance.Parse(xdoc.Root) with
| :? Storyboard as sb ->
sb.Scenes
//TODO: Support Xibs!
| :? Xib as xib -> failwith "Xib files are currently not supported"
| _ -> failwith "Could not parse file, no storyboard or xib types were found"
let types =
viewControllerElements
|> Seq.map (fun vc -> TypeBuilder.buildTypes designerFile vc isAbstract addUnitCtor register)
scenes
|> Seq.map (fun controller -> TypeBuilder.buildTypes designerFile controller.ViewController isAbstract addUnitCtor register config)
//Add the types to the container
for pt in types do