/// <summary> /// /// </summary> /// <param name="newFormular"></param> /// <param name="append"></param> /// private void UpdateWindow(MessageFormular newFormular, bool append = false) { if (newFormular == null) { return; } var old = LayoutPanel.Formular; // retrieve copy newFormular = newFormular.Clone() as MessageFormular; // act on copy if (append) { // overwrite all existing fields, and hand back the result foreach (var field in newFormular.FieldDescriptors) { old[field.Name] = field; // hard overwrite } old.Require(RequireEnum.NoneButBoth, newFormular); old.Name = newFormular.Name; newFormular = old; } else { newFormular.Require(RequireEnum.NoneButBoth, old); } LayoutPanel.Changed -= ReadLayoutPanel; LayoutPanel.Formular = newFormular; LayoutPanel.Changed += ReadLayoutPanel; LayoutPanel.CanEditFields = newFormular.IsDynamic; }
private void OnConfig(IDiffSpread <string> spread) { if (!SkippedFirst) { // usually just the Default of the pin, any saved data will come next SkippedFirst = true; return; // default of the pin already mimmicks default Formular for this node } var formular = Formular; formular.Require(RequireEnum.None); if (FFormularSelection.IsAnyInvalid()) { formular.Name = MessageFormular.DYNAMIC; } else { formular.Name = FFormularSelection[0].Name; } // overwrite fiels that occur in FConfig var config = new MessageFormular(MessageFormular.DYNAMIC, FConfig[0]); foreach (var field in config.FieldDescriptors) { formular[field.Name] = field; } Formular = formular; }
/// <summary> /// This will be called when a Formular is changed in the registry, to make all affected nodes comply with potential re-configuration /// </summary> /// <param name="sender">Usually Context</param> /// <param name="e">Contains the new Formular</param> protected virtual void FormularRemotelyChanged(MessageFormularRegistry sender, MessageFormular formular) { if (FFormularSelection.IsAnyInvalid()) { return; // before and during first frame input pins might not be valid yet } if (formular.IsDynamic) { return; } if (FFormularSelection[0] == formular.Name) { formular = formular.Clone() as MessageFormular; // keep a copy if (CustomizeFormular) { formular.Require(RequireEnum.NoneBut, Formular); // never automatically add anything. e.g never add pins without user consent } else { formular.Require(RequireEnum.All); // always add all. } Formular = formular; } }
/// <summary> /// Will try to apply the formular to the current pin layout /// </summary> /// <param name="newFormular"></param> /// <remarks> /// If any pin in the new formular is already present, it will preserve the pin. /// If any current pin is not contained in the new Formular, but is linked in the patch, it will force the node to raise exceptions every frame, until the link is manually deleted. /// </remarks> protected void TryDefinePins(object sender, MessageFormular newFormular) { // reject formular, deferring it to application later on. if (HasEndangeredLinks(newFormular)) { RemovePinsFirst = true; return; } else { RemovePinsFirst = false; } List <string> invalidPins = FPins.Keys.ToList(); foreach (FormularFieldDescriptor field in newFormular.FieldDescriptors.Where(field => field.IsRequired)) { if (FPins.ContainsKey(field.Name) && FPins[field.Name] != null) { invalidPins.Remove(field.Name); // same name, but types don't match // todo: in fact eg float does match double from vvvv side, conversion useful for patching speed? if (FPins[field.Name].GetInnerMostType() != field.Type) { FPins[field.Name].Dispose(); var pin = CreatePin(field); if (pin != null) { FPins[field.Name] = pin; } } } else { var pin = CreatePin(field); if (pin != null) { FPins[field.Name] = pin; } } } // cleanup foreach (string name in invalidPins) { FPins[name].Dispose(); FPins.Remove(name); } // reorder - does not work right now, sdk offers only read-only access //var names = Formular.FieldNames.ToArray(); //int counter = 0; //foreach (var name in newFormular.FieldNames) //{ // if (FPins[name] != null) // FPins[name].GetPluginIO().Order = counter * 2 + 5; //} }
protected virtual void OnSelectFormular(IDiffSpread <EnumEntry> spread) { if (FFormularSelection.IsAnyInvalid() || string.IsNullOrWhiteSpace(FFormularSelection[0].Name)) { FLogger.Log(LogType.Warning, "[\"" + this.GetType().Name + "\"] - Select a Formular. ID = " + PluginHost.GetNodePath(false)); return; } var formularName = FFormularSelection[0].Name; if (Formular.Name == formularName) { return; } if (formularName != MessageFormular.DYNAMIC) { Formular = RetrieveAdoptedFormular(formularName); } else { // fallback to what's been known to the node // so a switch to DYNAMIC keeps the old entries (but makes them editable) Formular.Name = MessageFormular.DYNAMIC; Formular = Formular; } }
public void MultipleDefinitions() { var reg = MessageFormularRegistry.Context; var formular = new MessageFormular("A38", "string[3] Field"); string lastChangedFormular = ""; reg.FormularChanged += (sender, newFormular) => lastChangedFormular = newFormular.Name; Assert.AreEqual("", lastChangedFormular); var success = reg.Define("AddFormular", formular); Assert.IsTrue(success); Assert.AreEqual("A38", lastChangedFormular); try { reg.Define("Clash", formular); Assert.Fail("Formular by that name already exists from a different definer."); } catch (RegistryException) {} success = reg.Undefine("AddFormular", formular); Assert.IsTrue(success); success = reg.Define("NoClash", formular); Assert.IsTrue(success); var definitions = reg.AllFormularNames.Where(x => x != MessageFormular.DYNAMIC); Assert.AreEqual(1, definitions.Count()); Assert.AreEqual("A38", definitions.First()); }
internal MessageFormularRegistry() { var formular = new MessageFormular(MessageFormular.DYNAMIC, null as Message); // empty message Data["_dyn"] = new List<MessageFormular>(); Data["_dyn"].Add(formular); }
//called when data for any output pin is requested public override void Evaluate(int SpreadMax) { var FieldCount = Getters.Count; if (FLearn[0] && FInput.SliceCount > 0 && FInput[0] != null) { var type = FInput[0].GetType(); FLogger.Log(LogType.Debug, "Learning Type... " + type.FullName); FieldInfo[] fields = type.GetFields(); FieldCount = fields.Length; FName.SliceCount = FieldCount; Getters.Clear(); var formular = new MessageFormular(type.FullName, ""); for (var i = 0; i < FieldCount; i++) { var name = fields[i].Name; FName[i] = name; var fieldInfo = type.GetField(name); try { formular.Append(new FormularFieldDescriptor(fieldInfo.FieldType, name, 1), true); var getter = fieldInfo.CompileGetter(); Getters.Add(name, getter); FLogger.Log(LogType.Debug, "Success: " + fieldInfo.FieldType.Name + " " + name); } catch (Exception) { FLogger.Log(LogType.Debug, "Failed: " + fieldInfo.FieldType.Name + " " + name); //FLogger.Log(ex, LogType.Debug); } } Formular = formular; } SpreadMax = FInput.SliceCount; FOutput.SliceCount = SpreadMax; for (int i = 0; i < SpreadMax; i++) { var m = new Message(Formular.Name); foreach (var fieldName in Formular.FieldNames) { var getter = Getters[fieldName]; var bin = BinFactory.New(Formular[fieldName].Type); bin.Add(getter(FInput[i])); m[fieldName] = bin; } FOutput[i] = m; } }
//called when data for any output pin is requested public override void Evaluate(int SpreadMax) { var FieldCount = Getters.Count; if (FLearn[0] && FInput.SliceCount > 0 && FInput[0] != null) { var type = FInput[0].GetType(); FLogger.Log(LogType.Debug, "Learning Type... "+type.FullName); FieldInfo[] fields = type.GetFields(); FieldCount = fields.Length; FName.SliceCount = FieldCount; Getters.Clear(); var formular = new MessageFormular(type.FullName, ""); for (var i = 0; i < FieldCount; i++) { var name = fields[i].Name; FName[i] = name; var fieldInfo = type.GetField(name); try { formular.Append(new FormularFieldDescriptor(fieldInfo.FieldType, name, 1), true); var getter = fieldInfo.CompileGetter(); Getters.Add(name, getter); FLogger.Log(LogType.Debug, "Success: " + fieldInfo.FieldType.Name + " " + name); } catch (Exception) { FLogger.Log(LogType.Debug, "Failed: " + fieldInfo.FieldType.Name + " " + name); //FLogger.Log(ex, LogType.Debug); } } Formular = formular; } SpreadMax = FInput.SliceCount; FOutput.SliceCount = SpreadMax; for (int i = 0; i < SpreadMax; i++) { var m = new Message(Formular.Name); foreach (var fieldName in Formular.FieldNames) { var getter = Getters[fieldName]; var bin = BinFactory.New(Formular[fieldName].Type); bin.Add(getter(FInput[i])); m[fieldName] = bin; } FOutput[i] = m; } }
public override void Evaluate(int SpreadMax) { // graceful fallback when being fed bad data if (FNew.IsAnyInvalid() || FTopic.IsAnyInvalid() || FSpreadCount.IsAnyInvalid()) { FOutput.FlushNil(); return; } if (!FNew.Any() && !ForceNewDefaults) { FOutput.FlushNil(); return; } SpreadMax = FFormularSelection.SliceCount; // numbers of supported Formulars FOutput.SliceCount = SpreadMax; var counter = 0; for (int i = 0; i < SpreadMax; i++) { var formularName = FFormularSelection[i].Name; MessageFormular formular; try { formular = RetrieveRegisteredFormular(formularName); } catch (RegistryException) { formular = null; } if (formular == null || formular.IsDynamic) { formular = new MessageFormular(formularName, ""); // empty fallback, in case not available or dynamic } FOutput[i].SliceCount = 0; var count = FSpreadCount[i]; for (int j = 0; j < count; j++) { if (FNew[counter] || ForceNewDefaults) { Message message = new Message(formular); message.Topic = FTopic[counter]; FOutput[i].Add(message); } counter++; } } FOutput.Flush(); ForceNewDefaults = false; }
/// <summary> /// Will try to apply the formular to the current pin layout /// </summary> /// <param name="newFormular"></param> /// <remarks> /// If any pin in the new formular is already present, it will preserve the pin. /// If any current pin is not contained in the new Formular, but is linked in the patch, it will force the node to raise exceptions every frame, until the link is manually deleted. /// </remarks> protected void TryDefinePins(object sender, MessageFormular newFormular) { // reject formular, deferring it to application later on. if (HasEndangeredLinks(newFormular)) { RemovePinsFirst = true; return; } else { RemovePinsFirst = false; } List <string> invalidPins = FPins.Keys.ToList(); foreach (FormularFieldDescriptor field in newFormular.FieldDescriptors.Where(field => field.IsRequired)) { if (FPins.ContainsKey(field.Name) && FPins[field.Name] != null) { invalidPins.Remove(field.Name); // same name, but types don't match // todo: in fact eg float does match double from vvvv side, conversion useful for patching speed? if (FPins[field.Name].GetTypeRecord().Type != field.Type) { FPins[field.Name].Dispose(); var pin = CreatePin(field); if (pin != null) { FPins[field.Name] = pin; } } } else { var pin = CreatePin(field); if (pin != null) { FPins[field.Name] = pin; } } } // cleanup foreach (string name in invalidPins) { FPins[name].Dispose(); FPins.Remove(name); } ReOrder(); }
protected virtual void OnConfigChange(IDiffSpread<string> configSpread) { var formular = new MessageFormular(MessageFormular.DYNAMIC, configSpread[0] ?? "string Value"); if (formular.FieldNames.Count() < 1) return; if (FValue != null) { FValue.Dispose(); } var name = formular.FieldNames.First(); TargetDynamicType = formular[name].Type; IOAttribute attr = DefinePin(formular[name]); // each implementation of DynamicNode must create its own InputAttribute or OutputAttribute Type pinType = typeof(ISpread<>).MakeGenericType((typeof(ISpread<>)).MakeGenericType(TargetDynamicType)); // the Pin is always a binsized one FValue = FIOFactory.CreateIOContainer(pinType, attr); }
/// <summary> /// This will be called when a Formular is changed in the registry, to make all affected nodes comply with potential re-configuration /// </summary> /// <param name="sender">Usually Context</param> /// <param name="e">Contains the new Formular</param> protected virtual void FormularRemotelyChanged(MessageFormularRegistry sender, MessageFormular formular) { if (FFormularSelection.IsAnyInvalid()) { return; // before and during first frame input pins might not be valid yet } if (formular.IsDynamic) { return; } if (FFormularSelection[0] == formular.Name) { formular = RetrieveAdoptedFormular(formular.Name); if (!CustomizeFormular) { formular.Require(RequireEnum.All); // always add all. } Formular = formular; } }
protected virtual void OnSelectFormular(IDiffSpread <EnumEntry> spread) { if (FFormularSelection.IsAnyInvalid() || string.IsNullOrWhiteSpace(FFormularSelection[0].Name)) { FLogger.Log(LogType.Warning, "[\"" + this.GetType().Name + "\"] - Select a Formular. ID = " + PluginHost.GetNodePath(false)); return; } var formularName = FFormularSelection[0].Name; if (Formular.Name == formularName) { return; } var backup = new MessageFormular(formularName, FConfig[0]); // local backup try { MessageFormular formular; if (formularName != MessageFormular.DYNAMIC) { formular = RetrieveFormular(formularName); formular.Require(RequireEnum.NoneBut, backup); } else { formular = backup; // fallback to what's been known to the node formular.Name = formularName; } Formular = formular; } catch (RegistryException) { // i.e. not found. might happen during first frame Formular = backup; } }
/// <summary> /// Detects link breaking action, that would occur when disposing a now unneeded pin, or resetting its type. /// </summary> /// <param name="newFormular">Includes the changes to be done.</param> /// <returns>True, if no linkbreaking conflict of type or linkbreaking pin elimination</returns> /// <remarks>Compares the existing dynamic pins with the required fields in the given Formular</remarks> protected bool HasEndangeredLinks(MessageFormular newFormular) { // pin removals var danger = from pinName in FPins.Keys where HasLink(FPins[pinName]) where !(newFormular.FieldNames.Contains(pinName) && newFormular[pinName].IsRequired) select pinName; // type changes - removal and recreate new var typeDanger = from pinName in FPins.Keys where HasLink(FPins[pinName]) // first frame pin will not be initialized where newFormular.FieldNames.Contains(pinName) where newFormular[pinName].IsRequired let innerType = FPins[pinName].GetTypeRecord().Type // ISpread<ISpread< ??? >> where newFormular[pinName].Type != innerType // rather ask for conversion? see actual pin creation for more comments select pinName; // ignore changes to binsize for now return(danger.Count() > 0 || typeDanger.Count() > 0); }
private MessageFormular RetrieveAdoptedFormular(string formularName) { MessageFormular reg; try { reg = RetrieveRegisteredFormular(formularName); } catch (RegistryException) { reg = new MessageFormular(MessageFormular.DYNAMIC, FConfig[0]); // i.e. not found. might happen during first frame } reg.Require(RequireEnum.NoneBut, Formular); var formular = new MessageFormular(formularName, ""); // all required fields, in order as the old one // overwrites any type differences, or sizes var oldNames = Formular.FieldNames.ToList(); var required = reg.FieldDescriptors.Where(f => f.IsRequired).OrderBy(f => oldNames.IndexOf(f.Name)); foreach (var field in required) { formular.Append(field, true); } // all non-required fields, in order as from registry var extraNames = reg.FieldNames.ToList(); var extra = reg.FieldDescriptors.Where(f => !f.IsRequired).OrderBy(f => extraNames.IndexOf(f.Name)); foreach (var field in extra) { formular.Append(field, false); } return(formular); }
protected virtual void OnConfigChange(IDiffSpread <string> configSpread) { var formular = new MessageFormular(MessageFormular.DYNAMIC, configSpread[0] ?? "string Value"); if (formular.FieldNames.Count() < 1) { return; } if (FValue != null) { FValue.Dispose(); } var name = formular.FieldNames.First(); TargetDynamicType = formular[name].Type; IOAttribute attr = DefinePin(formular[name]); // each implementation of DynamicNode must create its own InputAttribute or OutputAttribute Type pinType = typeof(ISpread <>).MakeGenericType((typeof(ISpread <>)).MakeGenericType(TargetDynamicType)); // the Pin is always a binsized one FValue = FIOFactory.CreateIOContainer(pinType, attr); }
protected virtual void OnSelectFormular(IDiffSpread<EnumEntry> spread) { if (FFormularSelection.IsAnyInvalid() || string.IsNullOrWhiteSpace( FFormularSelection[0].Name) ) { FLogger.Log(LogType.Warning, "[\""+ this.GetType().Name + "\"] - Select a Formular. ID = " + PluginHost.GetNodePath(false)); return; } var formularName = FFormularSelection[0].Name; if (Formular.Name == formularName) return; var backup = new MessageFormular(formularName, FConfig[0]); // local backup try { MessageFormular formular; if (formularName != MessageFormular.DYNAMIC) { formular = RetrieveFormular(formularName); formular.Require(RequireEnum.NoneBut, backup); } else { formular = backup; // fallback to what's been known to the node formular.Name = formularName; } Formular = formular; } catch (RegistryException) { // i.e. not found. might happen during first frame Formular = backup; } }
/// <summary> /// /// </summary> /// <param name="newFormular"></param> /// <param name="append"></param> /// private void UpdateWindow(MessageFormular newFormular, bool append = false) { if (newFormular == null) return; var old = LayoutPanel.Formular; // retrieve copy newFormular = newFormular.Clone() as MessageFormular; // act on copy if (append) { // overwrite all existing fields, and hand back the result foreach (var field in newFormular.FieldDescriptors) { old[field.Name] = field; // hard overwrite } old.Require(RequireEnum.NoneButBoth, newFormular); old.Name = newFormular.Name; newFormular = old; } else { newFormular.Require(RequireEnum.NoneButBoth, old); } LayoutPanel.Changed -= ReadLayoutPanel; LayoutPanel.Formular = newFormular; LayoutPanel.Changed += ReadLayoutPanel; LayoutPanel.CanEditFields = newFormular.IsDynamic; }
private void ReadLayoutPanel(object sender, MessageFormular formular) { Formular = formular; }
/// <summary> /// Will try to apply the formular to the current pin layout /// </summary> /// <param name="newFormular"></param> /// <remarks> /// If any pin in the new formular is already present, it will preserve the pin. /// If any current pin is not contained in the new Formular, but is linked in the patch, it will force the node to raise exceptions every frame, until the link is manually deleted. /// </remarks> protected void TryDefinePins(object sender, MessageFormular newFormular) { // reject formular, deferring it to application later on. if (HasEndangeredLinks(newFormular)) { RemovePinsFirst = true; return; } else RemovePinsFirst = false; List<string> invalidPins = FPins.Keys.ToList(); foreach (FormularFieldDescriptor field in newFormular.FieldDescriptors.Where(field => field.IsRequired)) { if (FPins.ContainsKey(field.Name) && FPins[field.Name] != null) { invalidPins.Remove(field.Name); // same name, but types don't match // todo: in fact eg float does match double from vvvv side, conversion useful for patching speed? if (FPins[field.Name].GetTypeRecord().Type != field.Type) { FPins[field.Name].Dispose(); var pin = CreatePin(field); if (pin != null) FPins[field.Name] = pin; } } else { var pin = CreatePin(field); if (pin != null) FPins[field.Name] = pin; } } // cleanup foreach (string name in invalidPins) { FPins[name].Dispose(); FPins.Remove(name); } ReOrder(); }
/// <summary> /// Detects link breaking action, that would occur when disposing a now unneeded pin, or resetting its type. /// </summary> /// <param name="newFormular">Includes the changes to be done.</param> /// <returns>True, if no linkbreaking conflict of type or linkbreaking pin elimination</returns> /// <remarks>Compares the existing dynamic pins with the required fields in the given Formular</remarks> protected bool HasEndangeredLinks(MessageFormular newFormular) { // pin removals var danger = from pinName in FPins.Keys where HasLink(FPins[pinName]) where !( newFormular.FieldNames.Contains(pinName) && newFormular[pinName].IsRequired) select pinName; // type changes - removal and recreate new var typeDanger = from pinName in FPins.Keys where HasLink(FPins[pinName]) // first frame pin will not be initialized where newFormular.FieldNames.Contains(pinName) where newFormular[pinName].IsRequired let innerType = FPins[pinName].GetTypeRecord().Type // ISpread<ISpread< ??? >> where newFormular[pinName].Type != innerType // rather ask for conversion? see actual pin creation for more comments select pinName; // ignore changes to binsize for now return danger.Count() > 0 || typeDanger.Count() > 0; }
public override void Evaluate(int SpreadMax) { // graceful fallback when being fed bad data if (FNew.IsAnyInvalid() || FTopic.IsAnyInvalid() || FSpreadCount.IsAnyInvalid()) { FOutput.FlushNil(); return; } if (!FNew.Any() && !ForceNewDefaults) { FOutput.FlushNil(); return; } SpreadMax = FFormularSelection.SliceCount; // numbers of supported Formulars FOutput.SliceCount = SpreadMax; var counter = 0; for (int i = 0; i < SpreadMax; i++) { var formularName = FFormularSelection[i].Name; MessageFormular formular; try { formular = RetrieveFormular(formularName); } catch (RegistryException) { formular = null; } if (formular == null || formular.IsDynamic) formular = new MessageFormular(formularName, ""); // empty fallback, in case not available or dynamic FOutput[i].SliceCount = 0; var count = FSpreadCount[i]; for (int j = 0; j < count; j++) { if (FNew[counter] || ForceNewDefaults) { Message message = new Message(formular); message.Topic = FTopic[counter]; FOutput[i].Add(message); } counter++; } } FOutput.Flush(); ForceNewDefaults = false; }
/// <summary> /// Unregisters a specific Formular from a specific definer source /// </summary> /// <param name="definerId"></param> /// <returns>true, if undefine had an effect.</returns> public bool Undefine(string definerId, MessageFormular formular) { if (!Data.ContainsKey(definerId)) return false; return Data[definerId].Remove(formular); }
private void OnConfig(IDiffSpread<string> spread) { if (!SkippedFirst) { // usually just the Default of the pin, any saved data will come next SkippedFirst = true; return; // default of the pin already mimmicks default Formular for this node } var formular = Formular; formular.Require(RequireEnum.None); if (FFormularSelection.IsAnyInvalid()) formular.Name = MessageFormular.DYNAMIC; else formular.Name = FFormularSelection[0].Name; // overwrite fiels that occur in FConfig var config = new MessageFormular(MessageFormular.DYNAMIC, FConfig[0]); foreach (var field in config.FieldDescriptors) { formular[field.Name] = field; } Formular = formular; }
public void Evaluate(int SpreadMax) { if (FConfiguration.IsAnyInvalid() || FName.IsAnyInvalid()) { return; } ForceUpdate |= !FUpdate.IsAnyInvalid() && FUpdate[0]; var change = ForceUpdate || FInherits.IsChanged || FName.IsChanged || FConfiguration.IsChanged; if (!ForceUpdate && !change) { if (_lastException != null) { FError.FlushItem(_lastException.ToString()); throw _lastException; } } // untoggle exception. if (_lastException != null) { var tmp = _lastException; FError.FlushItem(_lastException.ToString()); _lastException = null; // assume innocence throw tmp; } if (!change && !ForceUpdate) { return; } FOutput.SliceCount = SpreadMax = FName.SliceCount; var id = this.PluginHost.GetNodePath(false); var reg = MessageFormularRegistry.Context; for (int i = 0; i < SpreadMax; i++) { if (string.IsNullOrWhiteSpace(FName[i])) { _lastException = new ParseFormularException("A Formular cannot have an empty Name."); return; } var config = string.Join(", ", FConfiguration[i]).Split(','); var fields = new List <FormularFieldDescriptor>(); foreach (var def in config) { FormularFieldDescriptor field; try { field = new FormularFieldDescriptor(def.Trim(), true); } catch (ParseFormularException e) { _lastException = e; return; } var match = ( from f in fields where f.Name == field.Name select f ).FirstOrDefault(); if (match != null) { _lastException = new DuplicateFieldException("Cannot add \"" + def + "\" in Formular for [" + FName[i] + "]. Field with the same name already defined.", match, field); return; } else { fields.Add(field); } } var formular = new MessageFormular(FName[i], fields); if (!FInherits.IsAnyInvalid()) { // flatten var allFields = ( from form in FInherits from field in form.FieldDescriptors select field ).Distinct(); foreach (var field in allFields) { if (!formular.CanAppend(field)) { var duplicate = formular[field.Name]; _lastException = new DuplicateFieldException("Cannot add new Field \"" + field.ToString() + "\" to Formular [" + formular.Name + "]. Field is already defined as \"" + duplicate.ToString() + "\".", field, duplicate); return; } else { try { formular.Append(field, true); } catch (DuplicateFieldException e) { _lastException = e; return; } } } } // only register, when update has been hit! if (ForceUpdate) { try { var defined = reg.Define(id, formular); // will raise Change events to inform all formularable nodes if (defined) { FOutput[i] = formular; } } catch (RegistryException e) { _lastException = e; return; } }
/// <summary>Tries to define a Formular. Each named Formular can only be defined by one sender entity</summary> /// <param name="definerId">A unique string that helps to keep track, who registered a given Formular.</param> /// <param name="formular">A MessageFormular to be registered.</param> /// <param name="supressEvent">A bool indicating if the registry should skip informing interested parties about this change.</param> /// <exception cref="ArgumentNullException">Thrown when the Formular is null.</exception> /// <exception cref="RegistryException">This exception is thrown if a syntax error prevents the config to be parsed.</exception> /// <returns>success</returns> /// <remarks>Setting the supressEvent parameter to true will prevent this method to inform any TypeChanged subscribers.</remarks> public bool Define(string definerId, MessageFormular formular, bool supressEvent = false) { if (formular == null) throw new ArgumentNullException("Formular cannot be null"); if (formular.IsDynamic) return false; if (!Data.ContainsKey(definerId)) Data[definerId] = new List<MessageFormular>(); var conflict = ( from nodeId in Data.Keys where definerId != nodeId from form in Data[nodeId] where formular.Name == form.Name select form.Name ).FirstOrDefault(); if (conflict != null) { throw new RegistryException("Cannot add the formular to the registry. Another formular with the name \""+ conflict +"\" already exists."); } var ownFormulars = Data[definerId]; var oldForm = ( from form in ownFormulars where form.Name == formular.Name select form ).FirstOrDefault(); // no need to worry someone, if we conclude nothing's changed. // if (formular.Equals(oldForm)) return false; if (oldForm != null) ownFormulars.Remove(oldForm); ownFormulars.Add(formular); if (!supressEvent) { if (FormularChanged != null) FormularChanged(this, formular); } return true; }
protected bool LayoutByFormular(MessageFormular formular, bool keepUnused) { this.SuspendLayout(); var empty = Enumerable.Empty <FieldPanel>(); var prev = FieldPanels.ToList(); var unused = ( from panel in prev where panel.IsFaulty && panel.CanEdit select panel ).Concat( from panel in prev where !panel.IsFaulty && !panel.IsEmpty where !formular.FieldNames.Contains(panel.Descriptor.Name) select panel ).Distinct().ToList(); var remove = ( from panel in prev where !panel.IsFaulty where panel.IsEmpty || !formular.FieldNames.Contains(panel.Descriptor.Name) select panel ).Concat(keepUnused? empty : unused).Distinct().ToList(); // keep all that will var remain = ( from panel in prev where !panel.IsFaulty where !panel.IsEmpty where formular.FieldNames.Contains(panel.Descriptor.Name) select panel ).Concat(keepUnused? unused : empty).Distinct().ToList(); var currentDesc = ( from panel in prev where !panel.IsEmpty select panel.Descriptor.Name ); var fresh = ( from field in formular.FieldDescriptors where !currentDesc.Contains(field.Name) select field ).ToList(); var maxCount = remove.Count(); var counter = maxCount; foreach (var descriptor in fresh) { // if lingering panels available, recycle it or else instanciate new one if (counter > 0) { FieldPanel revive = remove[maxCount - counter]; revive.Descriptor = descriptor; // will modify the checkbox and description text revive.Visible = true; revive.Locked = Locked; counter--; } else { AddNewFieldPanel(descriptor); } } // cleanup: just keep them lingering around, recycle when needed. should speed up gui while (counter > 0) { FieldPanel panel = remove[maxCount - counter]; if (panel != null && !(panel.IsFaulty && keepUnused)) { panel.IsEmpty = true; // removes Checked as well } counter--; } // update remaining fields foreach (FieldPanel panel in remain) { if (!panel.IsFaulty) // don't touch faulty panels, user might want to fix them later. { var desc = formular[panel.Descriptor.Name]; desc.IsRequired = panel.Checked; panel.Descriptor = desc; // overwrite to stay in sync with the node's central formular } } this.ResumeLayout(); return(true); }
protected bool LayoutByFormular(MessageFormular formular, bool keepUnused) { this.SuspendLayout(); var empty = Enumerable.Empty<FieldPanel>(); var prev = FieldPanels.ToList(); var unused = ( from panel in prev where panel.IsFaulty && panel.CanEdit select panel ).Concat( from panel in prev where !panel.IsFaulty && !panel.IsEmpty where !formular.FieldNames.Contains(panel.Descriptor.Name) select panel ).Distinct().ToList(); var remove = ( from panel in prev where !panel.IsFaulty where panel.IsEmpty || !formular.FieldNames.Contains(panel.Descriptor.Name) select panel ).Concat(keepUnused? empty : unused).Distinct().ToList(); // keep all that will var remain = ( from panel in prev where !panel.IsFaulty where !panel.IsEmpty where formular.FieldNames.Contains(panel.Descriptor.Name) select panel ).Concat(keepUnused? unused : empty).Distinct().ToList(); var currentDesc = ( from panel in prev where !panel.IsEmpty select panel.Descriptor.Name ); var fresh = ( from field in formular.FieldDescriptors where !currentDesc.Contains(field.Name) select field ).ToList(); var maxCount = remove.Count(); var counter = maxCount; foreach (var descriptor in fresh) { // if lingering panels available, recycle it or else instanciate new one if (counter > 0) { FieldPanel revive = remove[maxCount - counter]; revive.Descriptor = descriptor; // will modify the checkbox and description text revive.Visible = true; revive.Locked = Locked; counter--; } else { AddNewFieldPanel(descriptor); } } // cleanup: just keep them lingering around, recycle when needed. should speed up gui while (counter > 0) { FieldPanel panel = remove[maxCount - counter]; if (panel != null && !(panel.IsFaulty && keepUnused)) panel.IsEmpty = true; // removes Checked as well counter--; } // update remaining fields foreach (FieldPanel panel in remain) { if (!panel.IsFaulty) // don't touch faulty panels, user might want to fix them later. { var desc = formular[panel.Descriptor.Name]; desc.IsRequired = panel.Checked; panel.Descriptor = desc; // overwrite to stay in sync with the node's central formular } } this.ResumeLayout(); return true; }
public void Evaluate(int SpreadMax) { if (FConfiguration.IsAnyInvalid() || FName.IsAnyInvalid()) return; ForceUpdate |= !FUpdate.IsAnyInvalid() && FUpdate[0]; var change = ForceUpdate || FInherits.IsChanged || FName.IsChanged || FConfiguration.IsChanged; if (!ForceUpdate && !change) { if (_lastException != null) { FError.FlushItem(_lastException.ToString()); throw _lastException; } } // untoggle exception. if (_lastException != null) { var tmp = _lastException; FError.FlushItem(_lastException.ToString()); _lastException = null; // assume innocence throw tmp; } if (!change && !ForceUpdate) return; FOutput.SliceCount = SpreadMax = FName.SliceCount; var id = this.PluginHost.GetNodePath(false); var reg = MessageFormularRegistry.Context; for (int i = 0; i < SpreadMax; i++) { if (string.IsNullOrWhiteSpace(FName[i])) { _lastException = new ParseFormularException("A Formular cannot have an empty Name."); return; } var config = string.Join(", ", FConfiguration[i]).Split(','); var fields = new List<FormularFieldDescriptor>(); foreach (var def in config) { FormularFieldDescriptor field; try { field = new FormularFieldDescriptor(def.Trim(), true); } catch (ParseFormularException e) { _lastException = e; return; } var match = ( from f in fields where f.Name == field.Name select f ).FirstOrDefault(); if (match != null) { _lastException = new DuplicateFieldException("Cannot add \"" + def + "\" in Formular for [" + FName[i] + "]. Field with the same name already defined.", match, field); return; } else fields.Add(field); } var formular = new MessageFormular(FName[i], fields); if (!FInherits.IsAnyInvalid()) { // flatten var allFields = ( from form in FInherits from field in form.FieldDescriptors select field ).Distinct(); foreach (var field in allFields) { if (!formular.CanAppend(field)) { var duplicate = formular[field.Name]; _lastException = new DuplicateFieldException("Cannot add new Field \"" + field.ToString() + "\" to Formular [" + formular.Name + "]. Field is already defined as \"" + duplicate.ToString() + "\".", field, duplicate); return; } else { try { formular.Append(field, true); } catch (DuplicateFieldException e) { _lastException = e; return; } } } } // only register, when update has been hit! if (ForceUpdate) try { var defined = reg.Define(id, formular); // will raise Change events to inform all formularable nodes if (defined) FOutput[i] = formular; } catch (RegistryException e) { _lastException = e; return; } catch (ArgumentNullException e) { _lastException = e; return; } } // only register, when update has been hit! if (ForceUpdate) { foreach (var form in reg.GetFormularsFrom(id).ToList()) { if (!FName.Contains(form.Name)) reg.Undefine(id, form); } FOutput.Flush(); EnumManager.UpdateEnum(MessageFormularRegistry.RegistryName, reg.AllFormularNames.First(), reg.AllFormularNames.ToArray()); } ForceUpdate = false; }
/// <summary> /// This will be called when a Formular is changed in the registry, to make all affected nodes comply with potential re-configuration /// </summary> /// <param name="sender">Usually Context</param> /// <param name="e">Contains the new Formular</param> protected virtual void FormularRemotelyChanged(MessageFormularRegistry sender, MessageFormular formular) { if (FFormularSelection.IsAnyInvalid()) return; // before and during first frame input pins might not be valid yet if (formular.IsDynamic) return; if (FFormularSelection[0] == formular.Name) { formular = formular.Clone() as MessageFormular; // keep a copy if (CustomizeFormular) formular.Require(RequireEnum.NoneBut, Formular); // never automatically add anything. e.g never add pins without user consent else formular.Require(RequireEnum.All); // always add all. Formular = formular; } }