private void PopulateCustomActionsDropDown() { customActionsToolStripMenuItem.DropDownItems.Clear(); if (File.Exists(ScriptEngine.CustomActionsJsonPath)) { custActions = CustomActionsJson.LoadFromJson(ScriptEngine.CustomActionsJsonPath); foreach (var action in custActions.Actions) { var item = customActionsToolStripMenuItem.DropDownItems.Add(action.Name); item.ToolTipText = action.Tooltip; item.AutoToolTip = true; item.Tag = action; item.Click += (s, e) => { var clickAction = CurrentCustomAction = (CustomActionJson)(s as ToolStripItem).Tag; txtAdvanced.Text = clickAction.Execute; }; } } if (custActions == null || custActions.Actions.Length == 0) { var item = customActionsToolStripMenuItem.DropDownItems.Add("(No custom actions)"); item.Enabled = false; } }
private void SaveCustomAction() { // TODO: Move this somewhere else using (var form = new SaveCustomActionForm()) { form.txtName.Text = CurrentCustomAction?.Name; form.txtTooltip.Text = CurrentCustomAction?.Tooltip; form.Context = CurrentCustomAction?.ValidContexts ?? UI.Selection.Context; var res = form.ShowDialog(); if (res == DialogResult.OK) { var act = new CustomActionJson(); act.Name = form.txtName.Text; act.Tooltip = form.txtTooltip.Text; act.Execute = txtAdvanced.Text; act.Enabled = "true"; act.ValidContexts = form.Context; ScriptEngine.CompileCustomActions(new CustomActionsJson() { Actions = new[] { act } }); if (ScriptEngine.CustomActionError) { MessageBox.Show("Compile failed, custom action contains errors and cannot be saved.", "Validation failed", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } if (custActions == null) { custActions = new CustomActionsJson() { Actions = new CustomActionJson[0] } } ; // Remove any existing actions with the same name: custActions.Actions = custActions.Actions.Where(a => !a.Name.Equals(act.Name, StringComparison.InvariantCultureIgnoreCase)).ToArray(); var toRemove = UI.Actions.OfType <CustomAction>().FirstOrDefault(a => a.BaseName.Equals(act.Name, StringComparison.InvariantCultureIgnoreCase)); if (toRemove != null) { UI.Actions.Remove(toRemove); } var list = custActions.Actions.ToList(); list.Add(act); custActions.Actions = list.ToArray(); custActions.SaveToJson(ScriptEngine.CustomActionsJsonPath); CurrentCustomAction = act; ScriptEngine.AddCustomActions(UI.Actions); PopulateCustomActionsDropDown(); } } }
private void SaveCustomAction() { // TODO: Move this somewhere else var form = new SaveCustomActionForm(); form.Context = UI.Selection.Context; form.txtName.Text = CurrentCustomAction; var res = form.ShowDialog(); if (res == DialogResult.OK) { var act = new CustomActionJson(); act.Name = form.txtName.Text; act.Tooltip = form.txtTooltip.Text; act.Execute = txtAdvanced.Text; act.Enabled = "true"; act.ValidContexts = form.Context; if (custActions == null) { custActions = new CustomActionsJson() { Actions = new CustomActionJson[0] } } ; // Remove any existing actions with the same name: custActions.Actions = custActions.Actions.Where(a => !a.Name.Equals(act.Name, StringComparison.InvariantCultureIgnoreCase)).ToArray(); var toRemove = UI.Actions.OfType <CustomAction>().FirstOrDefault(a => a.BaseName.Equals(act.Name, StringComparison.InvariantCultureIgnoreCase)); if (toRemove != null) { UI.Actions.Remove(toRemove); } var list = custActions.Actions.ToList(); list.Add(act); custActions.Actions = list.ToArray(); custActions.SaveToJson(ScriptEngine.CustomActionsJsonPath); // Compile and add the newly created action: ScriptEngine.CompileCustomActions(new CustomActionsJson() { Actions = new [] { act } }); if (!ScriptEngine.CustomActionError) { ScriptEngine.AddCustomActions(UI.Actions); } PopulateCustomActionsDropDown(); } }
private static void InitPlugins(IList <Assembly> plugins) { Plugins = plugins; _pluginNamespaces = plugins.SelectMany(p => p.GetExportedTypes()).Select(t => new AssemblyNamespace { Assembly = t.Assembly, Namespace = t.Namespace }).Distinct().ToList(); try { if (!File.Exists(WrapperDllPath)) { (new FileInfo(WrapperDllPath)).Directory.Create(); OutputWrapperDll(); } else { // Check if WrapperDll is of same version as the TabularEditor.exe and same Compatibility Level. If not, output a new one: var wrapperVersion = FileVersionInfo.GetVersionInfo(WrapperDllPath); var currentVersion = Assembly.GetAssembly(typeof(TabularModelHandler)).GetName().Version; if (wrapperVersion.FileVersion != currentVersion.ToString()) { OutputWrapperDll(); } } if (File.Exists(CustomActionsJsonPath)) { Console.WriteLine("Loading custom actions from: " + CustomActionsJsonPath); var actions = CustomActionsJson.LoadFromJson(CustomActionsJsonPath); actions.SaveToJson(@"C:\TE\testactions.json"); CompileCustomActions(actions); } else { ScriptEngineStatus = "File not found: " + CustomActionsJsonPath; } } catch (Exception ex) { Debug.WriteLine(ex.Message); ScriptEngineStatus = "Error: " + ex.Message; } }
private static void InitCustomActions() { try { if (File.Exists(CustomActionsJsonPath)) { Console.WriteLine("Loading custom actions from: " + CustomActionsJsonPath); var actions = CustomActionsJson.LoadFromJson(CustomActionsJsonPath); CompileCustomActions(actions); } else { ScriptEngineStatus = "File not found: " + CustomActionsJsonPath; } } catch (Exception ex) { Debug.WriteLine(ex.Message); ScriptEngineStatus = "Error: " + ex.Message; } }
public static void CompileCustomActions(CustomActionsJson actions) { var sw = new Stopwatch(); sw.Start(); if (actions == null || actions.Actions.Length == 0) { return; } var code = GetCustomActionsCode(actions); code = AddOutputLineNumbers(code); code = ReplaceGlobalMethodCalls(code); var result = Compile(code); CustomActionError = false; if (result.Errors.Count > 0) { Console.WriteLine("Could not compile Custom Actions."); foreach (CompilerError err in result.Errors) { Console.WriteLine("Line {0}, col {1}: {2}", err.Line, err.Column, err.ErrorText); } CustomActionError = true; } else { var assembly = result.CompiledAssembly; var type = assembly.GetType("TabularEditor.Scripting.CustomActions"); var method = type.GetMethod("CreateCustomActions"); AddCustomActions = (Action <ModelActionManager>)Delegate.CreateDelegate(typeof(Action <ModelActionManager>), method); } sw.Stop(); CustomActionCompiletime = sw.ElapsedMilliseconds; }
private void PopulateCustomActionsDropDown() { customActionsToolStripMenuItem.DropDownItems.Clear(); if (File.Exists(ScriptEngine.CustomActionsJsonPath)) { custActions = CustomActionsJson.LoadFromJson(ScriptEngine.CustomActionsJsonPath); foreach (var act in custActions.Actions) { customActionsToolStripMenuItem.DropDownItems.Add(act.Name, null, (s, e) => { CurrentCustomAction = act.Name; txtAdvanced.Text = act.Execute; }); } } if (custActions == null || custActions.Actions.Length == 0) { var item = customActionsToolStripMenuItem.DropDownItems.Add("(No custom actions)"); item.Enabled = false; } }
private void DeleteCurrentCustomAction() { if (CurrentCustomAction == null) { return; } var dialogResult = MessageBox.Show($"Are you sure you want to delete the custom action [{ CurrentCustomAction.Name }] ?", "Confirm delete action", MessageBoxButtons.YesNo, MessageBoxIcon.Warning); if (dialogResult != DialogResult.Yes) { return; } if (custActions == null) { custActions = new CustomActionsJson() { Actions = new CustomActionJson[0] } } ; custActions.Actions = custActions.Actions.Where(a => !a.Name.Equals(CurrentCustomAction.Name, StringComparison.InvariantCultureIgnoreCase)).ToArray(); var toRemove = UI.Actions.OfType <CustomAction>().FirstOrDefault(a => a.BaseName.Equals(CurrentCustomAction.Name, StringComparison.InvariantCultureIgnoreCase)); if (toRemove != null) { UI.Actions.Remove(toRemove); } custActions.SaveToJson(ScriptEngine.CustomActionsJsonPath); CurrentCustomAction = null; PopulateCustomActionsDropDown(); }
public static void CompileCustomActions(CustomActionsJson actions) { if (actions == null || actions.Actions.Length == 0) { return; } var sw = new Stopwatch(); sw.Start(); var assemblyRefs = new List <string>(); var usings = new List <string>(); foreach (var act in actions.Actions) { act.CleansedCode = ParseAssemblyRefsAndUsings(act.Execute, out List <string> actionAssemblyRefs, out List <string> actionUsings); assemblyRefs.AddRange(actionAssemblyRefs); usings.AddRange(actionUsings); } var code = GetCustomActionsCode(actions); code = AddOutputLineNumbers(code); code = ReplaceGlobalMethodCalls(code); code = string.Format("{0}\n{1}", string.Join(Environment.NewLine, usings), code); var result = Compile(code, assemblyRefs, errorCallback); CustomActionError = result.Errors.Count > 0; if (!CustomActionError) { var assembly = result.CompiledAssembly; var type = assembly.GetType("TabularEditor.Scripting.CustomActions"); var method = type.GetMethod("__CreateCustomActions"); AddCustomActions = (Action <IList <IBaseAction> >)Delegate.CreateDelegate(typeof(Action <IList <IBaseAction> >), method); } sw.Stop(); CustomActionCompiletime = sw.ElapsedMilliseconds; void errorCallback(CompilerErrorCollection errors, string source) { Console.WriteLine("Could not compile Custom Actions."); var messages = errors.Cast <CompilerError>() .Select(e => $"({ e.Line + errors.Count },{ e.Column }) { (e.IsWarning ? "warning" : "error") } {e.ErrorNumber}: {e.ErrorText}").ToList(); messages.ForEach(Console.WriteLine); try { messages.Add(source); File.WriteAllLines(CustomActionsErrorLogPath, messages); } catch (Exception ex) { Console.WriteLine($"Failed to write to file [{ CustomActionsErrorLogPath }] { ex }"); } } }
private static string GetCustomActionsCode(CustomActionsJson actions) { var t1 = new string(' ', 4); var t2 = new string(' ', 8); var t3 = new string(' ', 12); var t4 = new string(' ', 16); var sb = new StringBuilder(); sb.AppendLine(@"namespace TabularEditor.Scripting { public static class CustomActions { public static void __CreateCustomActions(IList<TabularEditor.UI.Actions.IBaseAction> __am) {" ); for (var ix = 0; ix < actions.Actions.Length; ix++) { sb.Append(t3 + "__am.Add(__CustomAction"); sb.Append(ix); sb.AppendLine("());"); } CustomActionCount = actions.Actions.Length; var i = 0; sb.AppendLine(t2 + "}"); // End Method foreach (var act in actions.Actions) { sb.Append(t2 + "private static TabularEditor.UI.Actions.CustomAction __CustomAction"); sb.Append(i); sb.AppendLine("() {"); sb.AppendLine(t3 + "var __act = new TabularEditor.UI.Actions.CustomAction("); // EnabledDelegate: sb.Append(t4 + "(Selected, Model) => "); sb.Append(DelegateCode(act.Enabled, false)); sb.AppendLine(","); // ExecuteDelegate: sb.AppendLine(t4 + "(Selected, Model) => {"); sb.AppendLine(CUSTOMACTIONS_CODEINDICATOR); sb.AppendLine(act.CleansedCode); sb.AppendLine(t4 + "},"); // Name: sb.AppendLine(t4 + "@\"" + act.Name.Replace("\"", "\"\"") + "\");"); if (!string.IsNullOrEmpty(act.Tooltip)) { sb.Append(t3 + "__act.ToolTip = @\""); sb.Append(act.Tooltip.Replace("\"", "\"\"")); sb.AppendLine("\";"); } sb.Append(t3 + "__act.ValidContexts = (Context)"); sb.Append((int)act.ValidContexts); sb.AppendLine(";"); sb.AppendLine(); sb.AppendLine("return __act;"); sb.AppendLine(t2 + "}"); i++; } sb.AppendLine(t1 + "}"); // End Class sb.AppendLine("}"); // End Namespace // Add(new Action(calcContext, (s, m) => s.Table.AddMeasure(displayFolder: s.DisplayFolder).Edit(), (s, m) => @"Create New\Measure")); return(sb.ToString()); }
public FormMain() { Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("en-US"); InitializeComponent(); dlgOpenFile.Filter = "Tabular Model Files|*.bim;database.json|Power BI Files|*.pbit|All files|*.*"; dlgSaveFile.Filter = "Tabular Model Files|*.bim|Power BI Files|*.pbit|All files|*.*"; // For some reason, Visual Studio sometimes removes this from the FormMain.Designer.cs, making the // colors of the lines look ugly: propertyGrid1.LineColor = System.Drawing.SystemColors.InactiveBorder; // Assign our own custom Designer, to make sure we can handle property changes on multiple objects simultaneously: propertyGrid1.Site = new DesignerHost(); // "Select Namespace" button should only be visible if we have loaded any plug-ins: toolStripButton3.Visible = ScriptEngine.PluginNamespaces.Count > 0; SetupUIController(); txtFilter.Control.SetCueBanner("Filter"); ///// Populate custom actions and samples ///// // TODO: Do this somewhere else if (File.Exists(ScriptEngine.CustomActionsJsonPath)) { custActions = CustomActionsJson.LoadFromJson(ScriptEngine.CustomActionsJsonPath); foreach (var act in custActions.Actions) { customActionsToolStripMenuItem.DropDownItems.Add(act.Name, null, (s, e) => { CurrentCustomAction = act.Name; txtAdvanced.Text = act.Execute; }); } } if (custActions == null || custActions.Actions.Length == 0) { var item = customActionsToolStripMenuItem.DropDownItems.Add("(No custom actions)"); item.Enabled = false; } var tutorial = (samplesMenu.DropDownItems.Add("Tutorials") as ToolStripMenuItem).DropDownItems; var translations = (samplesMenu.DropDownItems.Add("Translations") as ToolStripMenuItem).DropDownItems; tutorial.Add("Loop through all selected columns", null, (s, e) => { txtAdvanced.InsertText( @"foreach(var column in Selected.Columns) { // column.DisplayFolder = ""Test""; }"); }); tutorial.Add("Loop through all selected tables", null, (s, e) => { txtAdvanced.InsertText( @"foreach(var table in Selected.Tables) { // table.IsHidden = false; }"); }); tutorial.Add("Loop through columns on all selected tables", null, (s, e) => { txtAdvanced.InsertText( @"foreach(var column in Selected.Tables.SelectMany(t => t.Columns)) { // column.DisplayFolder = ""test""; }"); }); tutorial.Add("Loop through columns on all tables conditionally", null, (s, e) => { txtAdvanced.InsertText( @"foreach(var column in Model.Tables.SelectMany(t => t.Columns)) { if(column.Name.EndsWith(""Key"")) { // column.IsHidden = true; } }"); }); translations.Add("Copy display folder to active translation", null, (s, e) => { txtAdvanced.InsertText( @"Selected.Measures.ForEach(item => item.TranslatedDisplayFolders[Selected.Culture] = item.DisplayFolder); Selected.Columns.ForEach(item => item.TranslatedDisplayFolders[Selected.Culture] = item.DisplayFolder); Selected.Hierarchies.ForEach(item => item.TranslatedDisplayFolders[Selected.Culture] = item.DisplayFolder);"); }); translations.Add("Copy display folder to all translations", null, (s, e) => { txtAdvanced.InsertText( @"Selected.Measures.ForEach(item => item.TranslatedDisplayFolders.SetAll(item.DisplayFolder)); Selected.Columns.ForEach(item => item.TranslatedDisplayFolders.SetAll(item.DisplayFolder)); Selected.Hierarchies.ForEach(item => item.TranslatedDisplayFolders.SetAll(item.DisplayFolder));"); }); }