#region License Information
/* HeuristicLab
* Copyright (C) 2002-2008 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 System.Text;
using HeuristicLab.Core;
using Netron.Diagramming.Core;
using System.Drawing;
using HeuristicLab.Collections;
using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
namespace HeuristicLab.Operators.Views.GraphVisualization {
[StorableClass]
public sealed class GraphVisualizationInfo : DeepCloneable {
private BidirectionalLookup operatorShapeInfoMapping;
[Storable]
private BidirectionalLookup OperatorShapeInfoMappingStore {
get { return this.operatorShapeInfoMapping; }
set {
IOperator op;
IOperatorShapeInfo shapeInfo;
foreach (KeyValuePair pair in value.FirstEnumerable) {
op = pair.Key;
shapeInfo = pair.Value;
shapeInfo.Icon = new Bitmap(op.ItemImage);
this.RegisterOperatorEvents(op);
this.operatorParameterCollectionMapping.Add(op, pair.Key.Parameters);
this.operatorShapeInfoMapping.Add(op, shapeInfo);
this.shapeInfos.Add(shapeInfo);
}
foreach (IOperator oper in value.FirstValues) {
foreach (IParameter param in oper.Parameters) {
this.parameterOperatorMapping.Add(param, oper);
IValueParameter opParam = param as IValueParameter;
if (opParam != null) {
this.RegisterOperatorParameterEvents(opParam);
shapeInfo = this.operatorShapeInfoMapping.GetByFirst(oper);
if (opParam.Value != null) {
this.connections.Add(new KeyValuePair(shapeInfo, param.Name), this.operatorShapeInfoMapping.GetByFirst(opParam.Value));
}
} else
this.RegisterParameterEvents(param);
}
}
}
}
private BidirectionalLookup> operatorParameterCollectionMapping;
private Dictionary parameterOperatorMapping;
private GraphVisualizationInfo() {
this.operatorShapeInfoMapping = new BidirectionalLookup();
this.operatorParameterCollectionMapping = new BidirectionalLookup>();
this.parameterOperatorMapping = new Dictionary();
this.shapeInfos = new ObservableSet();
this.connections = new ObservableDictionary, IOperatorShapeInfo>();
}
public GraphVisualizationInfo(OperatorGraph operatorGraph)
: this() {
this.OperatorGraph = operatorGraph;
foreach (IOperator op in operatorGraph.Operators)
if (!this.operatorShapeInfoMapping.ContainsFirst(op))
this.AddOperator(op);
this.UpdateInitialShape();
}
public override IDeepCloneable Clone(Cloner cloner) {
GraphVisualizationInfo clone = new GraphVisualizationInfo();
cloner.RegisterClonedObject(this, clone);
clone.operatorGraph = (OperatorGraph)cloner.Clone(this.operatorGraph);
clone.oldInitialShape = (IOperatorShapeInfo)cloner.Clone(this.oldInitialShape);
clone.oldInitialShapeColor = this.oldInitialShapeColor;
IOperator op;
IOperatorShapeInfo shapeInfo;
foreach (KeyValuePair pair in this.operatorShapeInfoMapping.FirstEnumerable) {
op = (IOperator)cloner.Clone(pair.Key);
shapeInfo = (IOperatorShapeInfo)cloner.Clone(pair.Value);
clone.RegisterOperatorEvents(op);
clone.operatorParameterCollectionMapping.Add(op, pair.Key.Parameters);
clone.operatorShapeInfoMapping.Add(op, shapeInfo);
clone.shapeInfos.Add(shapeInfo);
}
foreach (IOperator oper in clone.operatorShapeInfoMapping.FirstValues) {
foreach (IParameter param in oper.Parameters) {
clone.parameterOperatorMapping.Add(param, oper);
IValueParameter opParam = param as IValueParameter;
if (opParam != null) {
clone.RegisterOperatorParameterEvents(opParam);
shapeInfo = clone.operatorShapeInfoMapping.GetByFirst(oper);
if (opParam.Value != null) {
clone.connections.Add(new KeyValuePair(shapeInfo, param.Name), clone.operatorShapeInfoMapping.GetByFirst(opParam.Value));
}
} else
clone.RegisterParameterEvents(param);
}
}
return clone;
}
public event EventHandler InitialShapeChanged;
private void operatorGraph_InitialOperatorChanged(object sender, EventArgs e) {
this.UpdateInitialShape();
}
private void UpdateInitialShape() {
IOperatorShapeInfo old = this.oldInitialShape as OperatorShapeInfo;
if (old != null)
old.Color = oldInitialShapeColor;
OperatorShapeInfo newInitialShapeInfo = this.InitialShape as OperatorShapeInfo;
if (newInitialShapeInfo != null) {
oldInitialShapeColor = newInitialShapeInfo.Color;
newInitialShapeInfo.Color = Color.LightGreen;
}
oldInitialShape = this.InitialShape;
if (this.InitialShapeChanged != null)
this.InitialShapeChanged(this, new EventArgs());
}
[Storable]
private IOperatorShapeInfo oldInitialShape;
[Storable]
private Color oldInitialShapeColor;
public IOperatorShapeInfo InitialShape {
get {
IOperator op = this.operatorGraph.InitialOperator;
if (op == null)
return null;
return this.operatorShapeInfoMapping.GetByFirst(op);
}
set {
if (value == null)
this.OperatorGraph.InitialOperator = null;
else
this.OperatorGraph.InitialOperator = this.operatorShapeInfoMapping.GetBySecond(value);
}
}
private OperatorGraph operatorGraph;
[Storable]
public OperatorGraph OperatorGraph {
get { return this.operatorGraph; }
private set {
if (this.operatorGraph != null || value == null)
throw new InvalidOperationException("Could not set OperatorGraph");
this.operatorGraph = value;
this.operatorGraph.InitialOperatorChanged += new EventHandler(operatorGraph_InitialOperatorChanged);
this.operatorGraph.Operators.ItemsAdded += new HeuristicLab.Collections.CollectionItemsChangedEventHandler(Operators_ItemsAdded);
this.operatorGraph.Operators.ItemsRemoved += new HeuristicLab.Collections.CollectionItemsChangedEventHandler(Operators_ItemsRemoved);
this.operatorGraph.Operators.CollectionReset += new HeuristicLab.Collections.CollectionItemsChangedEventHandler(Operators_CollectionReset);
}
}
private ObservableSet shapeInfos;
public INotifyObservableCollectionItemsChanged ObserveableShapeInfos {
get { return this.shapeInfos; }
}
public IEnumerable OperatorShapeInfos {
get { return this.shapeInfos; }
}
public IOperator GetOperatorForShapeInfo(IOperatorShapeInfo shapeInfo) {
return this.operatorShapeInfoMapping.GetBySecond(shapeInfo);
}
private ObservableDictionary, IOperatorShapeInfo> connections;
public INotifyObservableDictionaryItemsChanged, IOperatorShapeInfo> ObservableConnections {
get { return this.connections; }
}
public IEnumerable, IOperatorShapeInfo>> Connections {
get { return this.connections; }
}
#region methods to manipulate operatorgraph by the shape info
internal void AddShapeInfo(IOperator op, IOperatorShapeInfo shapeInfo) {
this.RegisterOperatorEvents(op);
this.operatorParameterCollectionMapping.Add(op, op.Parameters);
this.operatorShapeInfoMapping.Add(op, shapeInfo);
this.shapeInfos.Add(shapeInfo);
foreach (IParameter param in op.Parameters)
this.AddParameter(op, param);
this.operatorGraph.Operators.Add(op);
}
internal void RemoveShapeInfo(IOperatorShapeInfo shapeInfo) {
IOperator op = this.operatorShapeInfoMapping.GetBySecond(shapeInfo);
this.operatorGraph.Operators.Remove(op);
}
internal void AddConnection(IOperatorShapeInfo shapeInfoFrom, string connectorName, IOperatorShapeInfo shapeInfoTo) {
IOperator opFrom = this.operatorShapeInfoMapping.GetBySecond(shapeInfoFrom);
IOperator opTo = this.operatorShapeInfoMapping.GetBySecond(shapeInfoTo);
IValueParameter param = (IValueParameter)opFrom.Parameters[connectorName];
param.Value = opTo;
}
internal void ChangeConnection(IOperatorShapeInfo shapeInfoFrom, string connectorName, IOperatorShapeInfo shapeInfoTo) {
IOperator opFrom = this.operatorShapeInfoMapping.GetBySecond(shapeInfoFrom);
IOperator opTo = this.operatorShapeInfoMapping.GetBySecond(shapeInfoTo);
IValueParameter param = (IValueParameter)opFrom.Parameters[connectorName];
param.Value = opTo;
}
internal void RemoveConnection(IOperatorShapeInfo shapeInfoFrom, string connectorName) {
IOperator opFrom = this.operatorShapeInfoMapping.GetBySecond(shapeInfoFrom);
IValueParameter param = (IValueParameter)opFrom.Parameters[connectorName];
param.Value = null;
}
#endregion
#region operator events
private void AddOperator(IOperator op) {
if (!this.operatorShapeInfoMapping.ContainsFirst(op)) {
this.RegisterOperatorEvents(op);
IOperatorShapeInfo shapeInfo = Factory.CreateOperatorShapeInfo(op);
this.operatorParameterCollectionMapping.Add(op, op.Parameters);
this.operatorShapeInfoMapping.Add(op, shapeInfo);
this.shapeInfos.Add(shapeInfo);
foreach (IParameter param in op.Parameters)
this.AddParameter(op, param);
}
}
private void RemoveOperator(IOperator op) {
this.DeregisterOperatorEvents(op);
foreach (IParameter param in op.Parameters)
this.RemoveParameter(op, param);
IOperatorShapeInfo shapeInfo = this.operatorShapeInfoMapping.GetByFirst(op);
this.operatorParameterCollectionMapping.RemoveByFirst(op);
this.operatorShapeInfoMapping.RemoveByFirst(op);
this.shapeInfos.Remove(shapeInfo);
}
private void OperatorBreakpointChanged(object sender, EventArgs e) {
IOperator op = (IOperator)sender;
IOperatorShapeInfo operatorShapeInfo = this.operatorShapeInfoMapping.GetByFirst(op);
if (op.Breakpoint) {
operatorShapeInfo.LineColor = Color.Red;
operatorShapeInfo.LineWidth = 2;
} else {
operatorShapeInfo.LineColor = Color.Black;
operatorShapeInfo.LineWidth = 1;
}
}
private void OperatorNameChanged(object sender, EventArgs e) {
IOperator op = (IOperator)sender;
IOperatorShapeInfo operatorShapeInfo = this.operatorShapeInfoMapping.GetByFirst(op);
operatorShapeInfo.Title = op.Name;
}
private void Operators_ItemsAdded(object sender, HeuristicLab.Collections.CollectionItemsChangedEventArgs e) {
foreach (IOperator op in e.Items)
this.AddOperator(op);
}
private void Operators_ItemsRemoved(object sender, HeuristicLab.Collections.CollectionItemsChangedEventArgs e) {
foreach (IOperator op in e.Items)
this.RemoveOperator(op);
}
private void Operators_CollectionReset(object sender, HeuristicLab.Collections.CollectionItemsChangedEventArgs e) {
foreach (IOperator op in e.OldItems)
this.RemoveOperator(op);
foreach (IOperator op in e.Items)
this.AddOperator(op);
}
private void RegisterOperatorEvents(IOperator op) {
op.Parameters.ItemsAdded += new CollectionItemsChangedEventHandler(Parameters_ItemsAdded);
op.Parameters.ItemsRemoved += new CollectionItemsChangedEventHandler(Parameters_ItemsRemoved);
op.Parameters.ItemsReplaced += new CollectionItemsChangedEventHandler(Parameters_ItemsReplaced);
op.Parameters.CollectionReset += new CollectionItemsChangedEventHandler(Parameters_CollectionReset);
op.NameChanged += new EventHandler(OperatorNameChanged);
op.BreakpointChanged += new EventHandler(OperatorBreakpointChanged);
}
private void DeregisterOperatorEvents(IOperator op) {
op.Parameters.ItemsAdded -= new CollectionItemsChangedEventHandler(Parameters_ItemsAdded);
op.Parameters.ItemsRemoved -= new CollectionItemsChangedEventHandler(Parameters_ItemsRemoved);
op.Parameters.ItemsReplaced -= new CollectionItemsChangedEventHandler(Parameters_ItemsReplaced);
op.Parameters.CollectionReset -= new CollectionItemsChangedEventHandler(Parameters_CollectionReset);
op.NameChanged -= new EventHandler(OperatorNameChanged);
op.BreakpointChanged -= new EventHandler(OperatorBreakpointChanged);
}
#endregion
#region parameter events
private void AddParameter(IOperator op, IParameter param) {
this.parameterOperatorMapping.Add(param, op);
IValueParameter opParam = param as IValueParameter;
if (opParam != null) {
this.RegisterOperatorParameterEvents(opParam);
IOperatorShapeInfo shapeInfo = this.operatorShapeInfoMapping.GetByFirst(op);
shapeInfo.AddConnector(param.Name);
if (opParam.Value != null) {
if (!this.operatorShapeInfoMapping.ContainsFirst(opParam.Value))
this.AddOperator(opParam.Value);
this.connections.Add(new KeyValuePair(shapeInfo, param.Name), this.operatorShapeInfoMapping.GetByFirst(opParam.Value));
}
} else
this.RegisterParameterEvents(param);
}
private void RemoveParameter(IOperator op, IParameter param) {
IValueParameter opParam = param as IValueParameter;
if (opParam != null) {
this.DeregisterOperatorParameterEvents(opParam);
IOperatorShapeInfo shapeInfo = this.operatorShapeInfoMapping.GetByFirst(op);
this.connections.Remove(new KeyValuePair(shapeInfo, param.Name));
shapeInfo.RemoveConnector(param.Name);
} else
this.DeregisterParameterEvents(param);
this.parameterOperatorMapping.Remove(param);
}
private void opParam_ValueChanged(object sender, EventArgs e) {
IValueParameter opParam = (IValueParameter)sender;
if (opParam != null) {
IOperator op = this.parameterOperatorMapping[opParam];
IOperatorShapeInfo shapeInfo = this.operatorShapeInfoMapping.GetByFirst(op);
KeyValuePair connectionFrom = new KeyValuePair(shapeInfo, opParam.Name);
if (opParam.Value == null)
this.connections.Remove(connectionFrom);
else {
if (!this.operatorShapeInfoMapping.ContainsFirst(opParam.Value))
this.AddOperator(opParam.Value);
this.connections[connectionFrom] = this.operatorShapeInfoMapping.GetByFirst(opParam.Value);
}
}
}
private void Parameters_ItemsAdded(object sender, CollectionItemsChangedEventArgs e) {
IObservableKeyedCollection parameterCollection = sender as IObservableKeyedCollection;
IOperator op = this.operatorParameterCollectionMapping.GetBySecond(parameterCollection);
foreach (IParameter param in e.Items)
AddParameter(op, param);
this.UpdateParameterLabels(op);
}
private void Parameters_ItemsRemoved(object sender, CollectionItemsChangedEventArgs e) {
IObservableKeyedCollection parameterCollection = sender as IObservableKeyedCollection;
IOperator op = this.operatorParameterCollectionMapping.GetBySecond(parameterCollection);
foreach (IParameter param in e.Items)
RemoveParameter(op, param);
this.UpdateParameterLabels(op);
}
private void Parameters_ItemsReplaced(object sender, CollectionItemsChangedEventArgs e) {
IObservableKeyedCollection parameterCollection = sender as IObservableKeyedCollection;
IOperator op = this.operatorParameterCollectionMapping.GetBySecond(parameterCollection);
foreach (IParameter param in e.OldItems)
RemoveParameter(op, param);
foreach (IParameter param in e.Items)
AddParameter(op, param);
this.UpdateParameterLabels(op);
}
private void Parameters_CollectionReset(object sender, CollectionItemsChangedEventArgs e) {
IObservableKeyedCollection parameterCollection = sender as IObservableKeyedCollection;
IOperator op = this.operatorParameterCollectionMapping.GetBySecond(parameterCollection);
foreach (IParameter param in e.OldItems)
RemoveParameter(op, param);
foreach (IParameter param in e.Items)
AddParameter(op, param);
this.UpdateParameterLabels(op);
}
private void RegisterOperatorParameterEvents(IValueParameter opParam) {
opParam.ValueChanged += new EventHandler(opParam_ValueChanged);
}
private void DeregisterOperatorParameterEvents(IValueParameter opParam) {
opParam.ValueChanged -= new EventHandler(opParam_ValueChanged);
}
private void RegisterParameterEvents(IParameter param) {
param.ToStringChanged += new EventHandler(param_ToStringChanged);
param.NameChanged += new EventHandler(param_NameChanged);
}
private void DeregisterParameterEvents(IParameter param) {
param.ToStringChanged -= new EventHandler(param_ToStringChanged);
param.NameChanged -= new EventHandler(param_NameChanged);
}
private void param_NameChanged(object sender, EventArgs e) {
IParameter param = (IParameter)sender;
IOperator op = this.parameterOperatorMapping[param];
this.UpdateParameterLabels(op);
}
private void param_ToStringChanged(object sender, EventArgs e) {
IParameter param = (IParameter)sender;
IOperator op = this.parameterOperatorMapping[param];
this.UpdateParameterLabels(op);
}
private void UpdateParameterLabels(IOperator op) {
IEnumerable parameters = op.Parameters.Where(p => !(p is IValueParameter));
IOperatorShapeInfo operatorShapeInfo = this.operatorShapeInfoMapping.GetByFirst(op);
if (parameters.Count() > 0)
operatorShapeInfo.UpdateLabels(parameters.Select(p => p.ToString()));
else
operatorShapeInfo.UpdateLabels(new List());
}
#endregion
}
}