Free cookie consent management tool by TermsFeed Policy Generator

source: branches/OptimizationNetworks/HeuristicLab.Networks/3.3/Programmable/ProgrammableNetworkItem.cs @ 11712

Last change on this file since 11712 was 11712, checked in by swagner, 9 years ago

#2205: Implemented review comments:

  • checked and adapted item images
File size: 14.7 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2014 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
22using HeuristicLab.Common;
23using HeuristicLab.Core;
24using HeuristicLab.Core.Networks;
25using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
26using HeuristicLab.Scripting;
27using Microsoft.CSharp;
28using System;
29using System.CodeDom.Compiler;
30using System.Collections.Generic;
31using System.Drawing;
32using System.IO;
33using System.Linq;
34using System.Reflection;
35using System.Text;
36
37namespace HeuristicLab.Networks.Programmable {
38  [Item("ProgrammableNetworkItem", "Abstract base class for programmable items of a network.")]
39  [StorableClass]
40  public abstract class ProgrammableNetworkItem : Item, IProgrammableNetworkItem {
41    public static new Image StaticItemImage {
42      get { return HeuristicLab.Common.Resources.VSImageLibrary.Class; }
43    }
44
45    #region Item Members
46    public override string ItemName {
47      get { return CompiledNetworkItem.ItemName; }
48    }
49    public override string ItemDescription {
50      get { return CompiledNetworkItem.ItemDescription; }
51    }
52    public override Image ItemImage {
53      get { return CompiledNetworkItem.ItemImage; }
54    }
55    #endregion
56
57    #region NamedItem Members
58    [Storable]
59    private string name;
60    public string Name {
61      get { return CompiledNetworkItem.Name; }
62      set { CompiledNetworkItem.Name = value; }
63    }
64    public bool CanChangeName {
65      get { return CompiledNetworkItem.CanChangeName; }
66    }
67    [Storable]
68    private string description;
69    public string Description {
70      get { return CompiledNetworkItem.Description; }
71      set { CompiledNetworkItem.Description = value; }
72    }
73    public virtual bool CanChangeDescription {
74      get { return CompiledNetworkItem.CanChangeDescription; }
75    }
76    public event EventHandler<CancelEventArgs<string>> NameChanging;
77    private void OnNameChanging(CancelEventArgs<string> e) {
78      var handler = NameChanging;
79      if (handler != null) handler(this, e);
80    }
81    public event EventHandler NameChanged;
82    private void OnNameChanged() {
83      var handler = NameChanged;
84      if (handler != null) handler(this, EventArgs.Empty);
85    }
86    public event EventHandler DescriptionChanged;
87    private void OnDescriptionChanged() {
88      var handler = DescriptionChanged;
89      if (handler != null) handler(this, EventArgs.Empty);
90    }
91    #endregion
92
93    #region NetworkItem Members
94    public INetworkItem Parent {
95      get { return CompiledNetworkItem.Parent; }
96    }
97    public IEnumerable<INetworkItem> Children {
98      get { return CompiledNetworkItem.Children; }
99    }
100    #endregion
101
102    protected virtual string CodeTemplate {
103      get { return ReadCodeTemplate("HeuristicLab.Networks.Programmable.ProgrammableNetworkItemCode.cs"); }
104    }
105    [Storable]
106    private string code;
107    public string Code {
108      get { return code; }
109      set {
110        if (!CanChangeCode) throw new NotSupportedException("Code cannot be changed.");
111        if (value != code) {
112          code = value;
113          OnCodeChanged();
114        }
115      }
116    }
117    private CompilerErrorCollection compileErrors;
118    public CompilerErrorCollection CompileErrors {
119      get { return compileErrors; }
120      protected set {
121        compileErrors = value;
122        OnCompileErrorsChanged();
123      }
124    }
125    public virtual bool CanChangeCode {
126      get { return false; }
127    }
128    [Storable]
129    private VariableStore variableStore;
130    public VariableStore VariableStore {
131      get { return variableStore; }
132    }
133
134    private Type compiledNetworkItemType;
135    private CompiledProgrammableNetworkItem compiledNetworkItem;
136    protected CompiledProgrammableNetworkItem CompiledNetworkItem {
137      get {
138        if (compiledNetworkItem == null)
139          CompiledNetworkItem = (CompiledProgrammableNetworkItem)Activator.CreateInstance(compiledNetworkItemType, this);
140        return compiledNetworkItem;
141      }
142      private set {
143        if (compiledNetworkItem != value) {
144          if (compiledNetworkItem != null) {
145            DeregisterCompiledNetworkItemEvents();
146            compiledNetworkItem.DeregisterEvents();
147          }
148          compiledNetworkItem = value;
149          if (compiledNetworkItem != null) {
150            RegisterCompiledNetworkItemEvents();
151            compiledNetworkItem.RegisterEvents();
152          }
153          OnToStringChanged();
154          OnItemImageChanged();
155          OnNameChanged();
156          OnDescriptionChanged();
157        }
158      }
159    }
160
161    [StorableConstructor]
162    protected ProgrammableNetworkItem(bool deserializing) : base(deserializing) { }
163    protected ProgrammableNetworkItem(ProgrammableNetworkItem original, Cloner cloner)
164      : base(original, cloner) {
165      // name and description are cloned in CompiledProgrammableNetworkItem
166      code = original.code;
167      if (original.compileErrors != null)
168        compileErrors = new CompilerErrorCollection(original.compileErrors);
169      variableStore = cloner.Clone(original.variableStore);
170      CompiledNetworkItem = cloner.Clone(original.compiledNetworkItem);
171    }
172    protected ProgrammableNetworkItem()
173      : base() {
174      name = "ProgrammableNetworkItem";
175      description = string.Empty;
176      code = CodeTemplate;
177      variableStore = new VariableStore();
178      Compile();
179    }
180    protected ProgrammableNetworkItem(string name)
181      : base() {
182      this.name = string.IsNullOrEmpty(name) ? string.Empty : name;
183      description = string.Empty;
184      code = CodeTemplate;
185      variableStore = new VariableStore();
186      Compile();
187    }
188    protected ProgrammableNetworkItem(string name, string description)
189      : base() {
190      this.name = string.IsNullOrEmpty(name) ? string.Empty : name;
191      this.description = string.IsNullOrEmpty(description) ? string.Empty : description;
192      code = CodeTemplate;
193      variableStore = new VariableStore();
194      Compile();
195    }
196
197    [StorableHook(HookType.AfterDeserialization)]
198    private void AfterDeserialization() {
199      Compile();
200    }
201
202    public override string ToString() {
203      return CompiledNetworkItem.ToString();
204    }
205
206    #region Compilation
207    public virtual void Compile() {
208      var codeProvider = new CSharpCodeProvider(
209        new Dictionary<string, string> {
210          {"CompilerVersion", "v4.0"}, // support C# 4.0 syntax
211        }
212      );
213      var compilerParams = new CompilerParameters {
214        GenerateExecutable = false,
215        GenerateInMemory = true,
216        IncludeDebugInformation = true,
217        WarningLevel = 4
218      };
219      compilerParams.ReferencedAssemblies.AddRange(
220        GetAssemblies().Select(a => a.Location).ToArray()
221      );
222      var results = codeProvider.CompileAssemblyFromSource(compilerParams, code);
223      CompileErrors = results.Errors;
224      if (results.Errors.HasErrors) {
225        var sb = new StringBuilder();
226        foreach (CompilerError error in results.Errors) {
227          sb.Append(error.Line).Append(':')
228            .Append(error.Column).Append(": ")
229            .AppendLine(error.ErrorText);
230        }
231        throw new InvalidOperationException(string.Format("Compilation of \"{0}\" failed:{1}{2}",
232          Name, Environment.NewLine, sb.ToString()));
233      }
234      compiledNetworkItemType = results.CompiledAssembly.GetTypes()
235          .Single(x => typeof(CompiledProgrammableNetworkItem).IsAssignableFrom(x));
236      CompiledNetworkItem = null;
237    }
238    public virtual IEnumerable<Assembly> GetAssemblies() {
239      var assemblies = AppDomain.CurrentDomain.GetAssemblies()
240        .Where(a => !a.IsDynamic && File.Exists(a.Location))
241        .ToList();
242      assemblies.Add(typeof(Microsoft.CSharp.RuntimeBinder.Binder).Assembly);  // for dlr functionality
243      return assemblies;
244    }
245    #endregion
246
247    public event EventHandler CodeChanged;
248    protected virtual void OnCodeChanged() {
249      var handler = CodeChanged;
250      if (handler != null) handler(this, EventArgs.Empty);
251    }
252    public event EventHandler CompileErrorsChanged;
253    protected virtual void OnCompileErrorsChanged() {
254      var handler = CompileErrorsChanged;
255      if (handler != null) handler(this, EventArgs.Empty);
256    }
257
258    #region CompiledNetworkItem Events
259    protected virtual void RegisterCompiledNetworkItemEvents() {
260      CompiledNetworkItem.ToStringChanged += CompiledNetworkItem_ToStringChanged;
261      CompiledNetworkItem.ItemImageChanged += CompiledNetworkItem_ItemImageChanged;
262      CompiledNetworkItem.NameChanging += CompiledNetworkItem_NameChanging;
263      CompiledNetworkItem.NameChanged += CompiledNetworkItem_NameChanged;
264      CompiledNetworkItem.DescriptionChanged += CompiledNetworkItem_DescriptionChanged;
265    }
266    protected virtual void DeregisterCompiledNetworkItemEvents() {
267      CompiledNetworkItem.ToStringChanged -= CompiledNetworkItem_ToStringChanged;
268      CompiledNetworkItem.ItemImageChanged -= CompiledNetworkItem_ItemImageChanged;
269      CompiledNetworkItem.NameChanging -= CompiledNetworkItem_NameChanging;
270      CompiledNetworkItem.NameChanged -= CompiledNetworkItem_NameChanged;
271      CompiledNetworkItem.DescriptionChanged -= CompiledNetworkItem_DescriptionChanged;
272    }
273    private void CompiledNetworkItem_ToStringChanged(object sender, EventArgs e) {
274      OnToStringChanged();
275    }
276    private void CompiledNetworkItem_ItemImageChanged(object sender, EventArgs e) {
277      OnItemImageChanged();
278    }
279    private void CompiledNetworkItem_NameChanging(object sender, CancelEventArgs<string> e) {
280      OnNameChanging(e);
281    }
282    private void CompiledNetworkItem_NameChanged(object sender, EventArgs e) {
283      OnNameChanged();
284    }
285    private void CompiledNetworkItem_DescriptionChanged(object sender, EventArgs e) {
286      OnDescriptionChanged();
287    }
288    #endregion
289
290    #region CompiledProgrammableNetworkItem
291    [Item("CompiledProgrammableNetworkItem", "Abstract base class for compiled programmable items of a network.")]
292    public abstract class CompiledProgrammableNetworkItem : Item, INetworkItem {
293      public static new Image StaticItemImage {
294        get { return HeuristicLab.Common.Resources.VSImageLibrary.Class; }
295      }
296
297      #region NamedItem Members
298      public string Name {
299        get { return Context.name; }
300        set {
301          if (!CanChangeName) throw new NotSupportedException("Name cannot be changed.");
302          if (!(Context.name.Equals(value) || (value == null) && (Context.name == string.Empty))) {
303            CancelEventArgs<string> e = value == null ? new CancelEventArgs<string>(string.Empty) : new CancelEventArgs<string>(value);
304            OnNameChanging(e);
305            if (!e.Cancel) {
306              Context.name = value == null ? string.Empty : value;
307              OnNameChanged();
308            }
309          }
310        }
311      }
312      public virtual bool CanChangeName {
313        get { return true; }
314      }
315      public string Description {
316        get { return Context.description; }
317        set {
318          if (!CanChangeDescription) throw new NotSupportedException("Description cannot be changed.");
319          if (!(Context.description.Equals(value) || (value == null) && (Context.description == string.Empty))) {
320            Context.description = value == null ? string.Empty : value;
321            OnDescriptionChanged();
322          }
323        }
324      }
325      public virtual bool CanChangeDescription {
326        get { return true; }
327      }
328
329      public event EventHandler<CancelEventArgs<string>> NameChanging;
330      protected virtual void OnNameChanging(CancelEventArgs<string> e) {
331        var handler = NameChanging;
332        if (handler != null) handler(this, e);
333      }
334      public event EventHandler NameChanged;
335      protected virtual void OnNameChanged() {
336        var handler = NameChanged;
337        if (handler != null) handler(this, EventArgs.Empty);
338        OnToStringChanged();
339      }
340      public event EventHandler DescriptionChanged;
341      protected virtual void OnDescriptionChanged() {
342        var handler = DescriptionChanged;
343        if (handler != null) handler(this, EventArgs.Empty);
344      }
345      #endregion
346
347      #region NetworkItem Members
348      private INetworkItem parent;
349      public INetworkItem Parent {
350        get { return parent; }
351        protected set {
352          if (value != parent) {
353            parent = value;
354          }
355        }
356      }
357      public virtual IEnumerable<INetworkItem> Children {
358        get { return Enumerable.Empty<INetworkItem>(); }
359      }
360      #endregion
361
362      protected ProgrammableNetworkItem Context { get; private set; }
363      private Variables variables;
364      protected Variables Variables {
365        get {
366          if (variables == null) variables = new Variables(Context.variableStore);
367          return variables;
368        }
369      }
370      protected dynamic Vars {
371        get { return Variables; }
372      }
373
374      protected CompiledProgrammableNetworkItem(CompiledProgrammableNetworkItem original, Cloner cloner)
375        : base(original, cloner) {
376        Context = cloner.Clone(original.Context);
377        Context.name = original.Context.name;
378        Context.description = original.Context.description;
379      }
380      protected CompiledProgrammableNetworkItem(ProgrammableNetworkItem context)
381        : base() {
382        Context = context;
383      }
384
385      public virtual void Initialize() {
386        Variables.Clear();
387      }
388
389      public override string ToString() {
390        return Name;
391      }
392
393      #region Events
394      public virtual void RegisterEvents() { }
395      public virtual void DeregisterEvents() { }
396      #endregion
397    }
398    #endregion
399
400    #region Helpers
401    protected virtual string ReadCodeTemplate(string templateName) {
402      using (var stream = Assembly.GetAssembly(this.GetType()).GetManifestResourceStream(templateName))
403      using (var reader = new StreamReader(stream)) {
404        return reader.ReadToEnd();
405      }
406    }
407    #endregion
408  }
409}
Note: See TracBrowser for help on using the repository browser.