#region License Information /* HeuristicLab * Copyright (C) 2002-2010 Heuristic and Evolutionary Algorithms Laboratory (HEAL) * * This file is part of HeuristicLab. * * HeuristicLab is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * HeuristicLab is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with HeuristicLab. If not, see . */ #endregion using System; using System.Collections.Generic; using System.Linq; using HeuristicLab.Collections; using HeuristicLab.Common; using HeuristicLab.Core; using HeuristicLab.Data; using HeuristicLab.Persistence.Default.CompositeSerializers.Storable; namespace HeuristicLab.Optimization { [Item("Run Collection", "Represents a collection of runs.")] [Creatable("Testing & Analysis")] [StorableClass] public class RunCollection : ItemCollection, IStringConvertibleMatrix, IStorableContent { public string Filename { get; set; } [StorableConstructor] protected RunCollection(bool deserializing) : base(deserializing) { } protected RunCollection(RunCollection original, Cloner cloner) : base(original, cloner) { resultNames = new List(original.resultNames); parameterNames = new List(original.parameterNames); dataTypes = new Dictionary>(); foreach (string s in original.dataTypes.Keys) dataTypes[s] = new HashSet(original.dataTypes[s]); constraints = new RunCollectionConstraintCollection(original.constraints.Select(x => cloner.Clone(x))); foreach (IRunCollectionConstraint constraint in constraints) constraint.ConstrainedValue = this; RegisterConstraintsEvents(); RegisterConstraintEvents(constraints); UpdateFiltering(true); } public override IDeepCloneable Clone(Cloner cloner) { return new RunCollection(this, cloner); } public RunCollection() : base() { Initialize(); } public RunCollection(int capacity) : base(capacity) { Initialize(); } public RunCollection(IEnumerable collection) : base(collection) { Initialize(); this.OnItemsAdded(collection); } private void Initialize() { parameterNames = new List(); resultNames = new List(); dataTypes = new Dictionary>(); constraints = new RunCollectionConstraintCollection(); RegisterConstraintsEvents(); } [Storable] private Dictionary> dataTypes; public IEnumerable GetDataType(string columnName) { if (!dataTypes.ContainsKey(columnName)) return new Type[0]; return dataTypes[columnName]; } [Storable] private RunCollectionConstraintCollection constraints; public RunCollectionConstraintCollection Constraints { get { return constraints; } } protected override void OnCollectionReset(IEnumerable items, IEnumerable oldItems) { parameterNames.Clear(); resultNames.Clear(); foreach (IRun run in items) { foreach (KeyValuePair parameter in run.Parameters) AddParameter(parameter.Key, parameter.Value); foreach (KeyValuePair result in run.Results) AddResult(result.Key, result.Value); } columnNameCache = null; OnColumnNamesChanged(); rowNamesCache = null; base.OnCollectionReset(items, oldItems); OnRowNamesChanged(); OnReset(); UpdateFiltering(false); } protected override void OnItemsAdded(IEnumerable items) { bool columnNamesChanged = false; foreach (IRun run in items) { foreach (KeyValuePair parameter in run.Parameters) columnNamesChanged |= AddParameter(parameter.Key, parameter.Value); foreach (KeyValuePair result in run.Results) columnNamesChanged |= AddResult(result.Key, result.Value); } if (columnNamesChanged) columnNameCache = null; rowNamesCache = null; base.OnItemsAdded(items); OnReset(); OnRowNamesChanged(); if (columnNamesChanged) OnColumnNamesChanged(); UpdateFiltering(false); } protected override void OnItemsRemoved(IEnumerable items) { bool columnNamesChanged = false; foreach (IRun run in items) { foreach (string parameterName in run.Parameters.Keys) columnNamesChanged |= RemoveParameterName(parameterName); foreach (string resultName in run.Results.Keys) columnNamesChanged |= RemoveResultName(resultName); } if (columnNamesChanged) columnNameCache = null; rowNamesCache = null; base.OnItemsRemoved(items); OnReset(); OnRowNamesChanged(); if (columnNamesChanged) OnColumnNamesChanged(); } private bool AddParameter(string name, IItem value) { if (value == null) return false; if (!parameterNames.Contains(name)) { parameterNames.Add(name); dataTypes[name] = new HashSet(); dataTypes[name].Add(value.GetType()); return true; } dataTypes[name].Add(value.GetType()); return false; } private bool AddResult(string name, IItem value) { if (value == null) return false; if (!resultNames.Contains(name)) { resultNames.Add(name); dataTypes[name] = new HashSet(); dataTypes[name].Add(value.GetType()); return true; } dataTypes[name].Add(value.GetType()); return false; } private bool RemoveParameterName(string name) { if (!list.Any(x => x.Parameters.ContainsKey(name))) { parameterNames.Remove(name); return true; } return false; } private bool RemoveResultName(string name) { if (!list.Any(x => x.Results.ContainsKey(name))) { resultNames.Remove(name); return true; } return false; } public IItem GetValue(int rowIndex, int columnIndex) { IRun run = this.list[rowIndex]; return GetValue(run, columnIndex); } public IItem GetValue(IRun run, int columnIndex) { string name = ((IStringConvertibleMatrix)this).ColumnNames.ElementAt(columnIndex); return GetValue(run, name); } public IItem GetValue(IRun run, string columnName) { IItem value = null; if (run.Parameters.ContainsKey(columnName)) value = run.Parameters[columnName]; else if (run.Results.ContainsKey(columnName)) value = run.Results[columnName]; return value; } [StorableHook(HookType.AfterDeserialization)] private void AfterDeserialization() { if (constraints == null) constraints = new RunCollectionConstraintCollection(); RegisterConstraintsEvents(); RegisterConstraintEvents(constraints); UpdateFiltering(true); } #region IStringConvertibleMatrix Members [Storable] private List parameterNames; public IEnumerable ParameterNames { get { return this.parameterNames; } } [Storable] private List resultNames; public IEnumerable ResultNames { get { return this.resultNames; } } int IStringConvertibleMatrix.Rows { get { return this.Count; } set { throw new NotSupportedException(); } } int IStringConvertibleMatrix.Columns { get { return parameterNames.Count + resultNames.Count; } set { throw new NotSupportedException(); } } private List columnNameCache; IEnumerable IStringConvertibleMatrix.ColumnNames { get { if (columnNameCache == null) { columnNameCache = new List(parameterNames); columnNameCache.AddRange(resultNames); columnNameCache.Sort(); } return columnNameCache; } set { throw new NotSupportedException(); } } private List rowNamesCache; IEnumerable IStringConvertibleMatrix.RowNames { get { if (rowNamesCache == null) rowNamesCache = list.Select(x => x.Name).ToList(); return rowNamesCache; } set { throw new NotSupportedException(); } } bool IStringConvertibleMatrix.SortableView { get { return true; } set { throw new NotSupportedException(); } } bool IStringConvertibleMatrix.ReadOnly { get { return true; } } string IStringConvertibleMatrix.GetValue(int rowIndex, int columnIndex) { IItem value = GetValue(rowIndex, columnIndex); if (value == null) return string.Empty; return value.ToString(); } public event EventHandler> ItemChanged; protected virtual void OnItemChanged(int rowIndex, int columnIndex) { EventHandler> handler = ItemChanged; if (handler != null) handler(this, new EventArgs(rowIndex, columnIndex)); OnToStringChanged(); } public event EventHandler Reset; protected virtual void OnReset() { EventHandler handler = Reset; if (handler != null) handler(this, EventArgs.Empty); OnToStringChanged(); } public event EventHandler ColumnNamesChanged; protected virtual void OnColumnNamesChanged() { EventHandler handler = ColumnNamesChanged; if (handler != null) handler(this, EventArgs.Empty); } public event EventHandler RowNamesChanged; protected virtual void OnRowNamesChanged() { EventHandler handler = RowNamesChanged; if (handler != null) handler(this, EventArgs.Empty); } public event EventHandler SortableViewChanged; protected virtual void OnSortableViewChanged() { EventHandler handler = SortableViewChanged; if (handler != null) handler(this, EventArgs.Empty); } public bool Validate(string value, out string errorMessage) { throw new NotSupportedException(); } public bool SetValue(string value, int rowIndex, int columnIndex) { throw new NotSupportedException(); } #endregion #region filtering private void UpdateFiltering(bool reset) { if (reset) list.ForEach(r => r.Visible = true); foreach (IRunCollectionConstraint constraint in this.constraints) constraint.Check(); } private void RegisterConstraintsEvents() { constraints.ItemsAdded += new CollectionItemsChangedEventHandler(Constraints_ItemsAdded); constraints.ItemsRemoved += new CollectionItemsChangedEventHandler(Constraints_ItemsRemoved); constraints.CollectionReset += new CollectionItemsChangedEventHandler(Constraints_CollectionReset); } protected virtual void RegisterConstraintEvents(IEnumerable constraints) { foreach (IRunCollectionConstraint constraint in constraints) { constraint.ActiveChanged += new EventHandler(Constraint_ActiveChanged); constraint.ConstrainedValueChanged += new EventHandler(Constraint_ConstrainedValueChanged); constraint.ConstraintOperationChanged += new EventHandler(Constraint_ConstraintOperationChanged); constraint.ConstraintDataChanged += new EventHandler(Constraint_ConstraintDataChanged); } } protected virtual void DeregisterConstraintEvents(IEnumerable constraints) { foreach (IRunCollectionConstraint constraint in constraints) { constraint.ActiveChanged -= new EventHandler(Constraint_ActiveChanged); constraint.ConstrainedValueChanged -= new EventHandler(Constraint_ConstrainedValueChanged); constraint.ConstraintOperationChanged -= new EventHandler(Constraint_ConstraintOperationChanged); constraint.ConstraintDataChanged -= new EventHandler(Constraint_ConstraintDataChanged); } } protected virtual void Constraints_CollectionReset(object sender, CollectionItemsChangedEventArgs e) { DeregisterConstraintEvents(e.OldItems); RegisterConstraintEvents(e.Items); this.UpdateFiltering(true); } protected virtual void Constraints_ItemsAdded(object sender, CollectionItemsChangedEventArgs e) { RegisterConstraintEvents(e.Items); foreach (IRunCollectionConstraint constraint in e.Items) constraint.ConstrainedValue = this; this.UpdateFiltering(false); } protected virtual void Constraints_ItemsRemoved(object sender, CollectionItemsChangedEventArgs e) { DeregisterConstraintEvents(e.Items); this.UpdateFiltering(true); } protected virtual void Constraint_ActiveChanged(object sender, EventArgs e) { IRunCollectionConstraint constraint = (IRunCollectionConstraint)sender; this.UpdateFiltering(!constraint.Active); } protected virtual void Constraint_ConstrainedValueChanged(object sender, EventArgs e) { //mkommend: this method is intentionally left empty, because the constrainedValue is set in the ItemsAdded method } protected virtual void Constraint_ConstraintOperationChanged(object sender, EventArgs e) { IRunCollectionConstraint constraint = (IRunCollectionConstraint)sender; if (constraint.Active) this.UpdateFiltering(true); } protected virtual void Constraint_ConstraintDataChanged(object sender, EventArgs e) { IRunCollectionConstraint constraint = (IRunCollectionConstraint)sender; if (constraint.Active) this.UpdateFiltering(true); } #endregion } }