namespace Actions { using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Windows; using System.Windows.Serialization; using System.Reflection; using System.Reflection.Emit; using IronPython.Compiler; using IronPython.Hosting; using IronPython.Runtime; [ContentProperty("Script"), DefaultProperty("Script")] public class PScriptlet: Action, IAddChild { public static readonly DependencyProperty ScriptProperty = DependencyProperty.Register("Script", PScriptlet.ScriptChanged); private Dict globals = new Dict(); private PythonModule module; private FrameCode code = null; static PScriptlet() { PythonEngine pe = new PythonEngine(); Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach(Assembly assembly in assemblies) if (!(assembly is AssemblyBuilder)) pe.LoadAssembly(assembly); } public PScriptlet() { this.module = new PythonModule("__main__", globals); Ops.ImportStar(module, "System.Windows"); Ops.ImportStar(module, "System.Windows.Controls"); Ops.ImportStar(module, "System.Windows.Media"); } public string Script { get { return PScriptlet.ScriptProperty.GetValue(this); } set { PScriptlet.ScriptProperty.SetValue(this, value); } } public override void Invoke() { // Set up the INameScope members as locals. NameScopeLocals locals = NameScopeLocals.CreateForObject(this.TriggerSource); Frame topFrame = new Frame(module, globals, locals); code.Run(topFrame); } protected override Freezable CreateInstanceCore() { return new PScriptlet(); } private static void ScriptChanged(PScriptlet scriptlet, string oldValue, string newValue) { CompilerContext context = new CompilerContext(); Parser p = Parser.FromString(context, newValue); Stmt statement = p.ParseFileInput(); scriptlet.code = OutputGenerator.GenerateSnippet(context, statement, "input", false); } public void AddChild(object value) { } public void AddText(string text) { this.Script += TrimWhitespace(text); } // Python depends on indentation for formatting, but that sorta messes up the XAML when inline. // This trims the leading whitespace using the first line for reference of how much needs to // be trimmed. private static string TrimWhitespace(string text) { string leadingWhitespace = text.Substring(0, text.Length - text.TrimStart(null).Length); if (leadingWhitespace.IndexOf('\t') != -1) leadingWhitespace = leadingWhitespace.Remove(0, leadingWhitespace.IndexOf('\t')); string[] lines = text.Split('\n'); string finalText = string.Empty; foreach (string line in lines) { string cleanLine = line; if (cleanLine.StartsWith(leadingWhitespace)) cleanLine = cleanLine.Substring(leadingWhitespace.Length); finalText += cleanLine + "\n"; } return finalText; } } /// /// Helper class to expose INameScope entries as global objects in the Python engine. /// public class NameScopeLocals : IDictionary { INameScope namescope; Dictionary locals = new Dictionary(); public NameScopeLocals(INameScope namescope) { this.namescope = namescope; } public static NameScopeLocals CreateForObject(object obj) { INameScope namescope = obj as INameScope; if (namescope != null) return new NameScopeLocals(namescope); DependencyObject dependencyObj = obj as DependencyObject; if (dependencyObj != null) { namescope = NameScope.GetNameScope(dependencyObj); if (namescope != null) return new NameScopeLocals(namescope); return CreateForObject(LogicalTreeHelper.GetParent(dependencyObj)); } return new NameScopeLocals(new NameScope()); } public void Add(object key, object value) { this.locals.Add(key, value); } public bool ContainsKey(object key) { if (this.locals.ContainsKey(key)) return true; return this.namescope.FindName(key.ToString()) != null; } public bool Remove(object key) { return this.locals.Remove(key); } public bool TryGetValue(object key, out object value) { if (this.locals.TryGetValue(key, out value)) return true; value = this.namescope.FindName(key.ToString()); return value != null; } public object this[object key] { get { object value = null; if (this.locals.TryGetValue(key, out value)) return value; value = this.namescope.FindName(key.ToString()); if (value == null) throw new KeyNotFoundException(); return value; } set { this.locals[key] = value; } } public void Add(KeyValuePair item) { this.Add(item.Key, item.Value); } public void Clear() { this.locals.Clear(); } public bool Contains(KeyValuePair item) { if (((IDictionary)this.locals).Contains(item)) return true; return this.namescope.FindName(item.Key.ToString()) == item.Value; } public void CopyTo(KeyValuePair[] array, int arrayIndex) { ((IDictionary)this.locals).CopyTo(array, arrayIndex); } public bool IsReadOnly { get { return false; } } public bool Remove(KeyValuePair item) { ((IDictionary)this.locals).Remove(item); return true; } public ICollection Keys { get { throw new NotImplementedException("The method or operation is not implemented."); } } public ICollection Values { get { throw new NotImplementedException("The method or operation is not implemented."); } } public int Count { get { throw new NotImplementedException("The method or operation is not implemented."); } } public IEnumerator> GetEnumerator() { throw new NotImplementedException("The method or operation is not implemented."); } System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { throw new NotImplementedException("The method or operation is not implemented."); } } }