Added real parser integration, removing prototype designer types
This commit is contained in:
Родитель
2bd78d53a5
Коммит
b8b692d1c6
|
@ -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
|
||||
|
|
Загрузка…
Ссылка в новой задаче