Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/HeuristicLab.Optimization/3.3/RunCollection.cs @ 17578

Last change on this file since 17578 was 17180, checked in by swagner, 5 years ago

#2875: Removed years in copyrights

File size: 22.5 KB
RevLine 
[3260]1#region License Information
2/* HeuristicLab
[17180]3 * Copyright (C) Heuristic and Evolutionary Algorithms Laboratory (HEAL)
[3260]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
[3329]22using System;
[3260]23using System.Collections.Generic;
[11344]24using System.ComponentModel;
[3260]25using System.Linq;
[4068]26using HeuristicLab.Collections;
[3376]27using HeuristicLab.Common;
[3260]28using HeuristicLab.Core;
[3329]29using HeuristicLab.Data;
[16565]30using HEAL.Attic;
[3260]31
32namespace HeuristicLab.Optimization {
[3716]33  [Item("Run Collection", "Represents a collection of runs.")]
[12504]34  [Creatable(CreatableAttribute.Categories.TestingAndAnalysis, Priority = 120)]
[16565]35  [StorableType("6A9E959B-62DB-4998-BFC6-BF3BAE66BED4")]
[4419]36  public class RunCollection : ItemCollection<IRun>, IStringConvertibleMatrix, IStorableContent {
37    public string Filename { get; set; }
38
[4164]39    [StorableConstructor]
[16565]40    protected RunCollection(StorableConstructorFlag _) : base(_) {
[4888]41      updateOfRunsInProgress = false;
42    }
[4722]43    protected RunCollection(RunCollection original, Cloner cloner)
44      : base(original, cloner) {
[4888]45      updateOfRunsInProgress = false;
[8962]46      optimizerName = original.optimizerName;
[8738]47
[4722]48      resultNames = new List<string>(original.resultNames);
49      parameterNames = new List<string>(original.parameterNames);
50      dataTypes = new Dictionary<string, HashSet<Type>>();
51      foreach (string s in original.dataTypes.Keys)
52        dataTypes[s] = new HashSet<Type>(original.dataTypes[s]);
53
54      constraints = new RunCollectionConstraintCollection(original.constraints.Select(x => cloner.Clone(x)));
[6693]55      modifiers = new CheckedItemList<IRunCollectionModifier>(original.modifiers.Select(cloner.Clone));
[4722]56      foreach (IRunCollectionConstraint constraint in constraints)
57        constraint.ConstrainedValue = this;
58      RegisterConstraintsEvents();
59      RegisterConstraintEvents(constraints);
60
[12022]61      foreach (var run in this) {
62        RegisterRunParametersEvents(run);
63        RegisterRunResultsEvents(run);
64      }
65
[4722]66      UpdateFiltering(true);
67    }
[3329]68    public RunCollection() : base() { Initialize(); }
69    public RunCollection(int capacity) : base(capacity) { Initialize(); }
70    public RunCollection(IEnumerable<IRun> collection) : base(collection) { Initialize(); this.OnItemsAdded(collection); }
[3447]71    private void Initialize() {
[4888]72      updateOfRunsInProgress = false;
[3447]73      parameterNames = new List<string>();
74      resultNames = new List<string>();
[3614]75      dataTypes = new Dictionary<string, HashSet<Type>>();
76      constraints = new RunCollectionConstraintCollection();
[6693]77      modifiers = new CheckedItemList<IRunCollectionModifier>();
[4164]78      RegisterConstraintsEvents();
[3447]79    }
[4164]80
[3625]81    [Storable]
[3614]82    private Dictionary<string, HashSet<Type>> dataTypes;
83    public IEnumerable<Type> GetDataType(string columnName) {
84      if (!dataTypes.ContainsKey(columnName))
85        return new Type[0];
86      return dataTypes[columnName];
87    }
[4164]88
89    [Storable]
[3614]90    private RunCollectionConstraintCollection constraints;
91    public RunCollectionConstraintCollection Constraints {
[3625]92      get { return constraints; }
[3614]93    }
[3329]94
[6693]95    [Storable]
96    private CheckedItemList<IRunCollectionModifier> modifiers;
97    public CheckedItemList<IRunCollectionModifier> Modifiers {
98      get { return modifiers; }
99    }
100
101
[4888]102    private bool updateOfRunsInProgress;
103    public bool UpdateOfRunsInProgress {
104      get { return updateOfRunsInProgress; }
105      set {
106        if (updateOfRunsInProgress != value) {
107          updateOfRunsInProgress = value;
108          OnUpdateOfRunsInProgressChanged();
109        }
110      }
111    }
112
[8962]113    private string optimizerName = string.Empty;
[8738]114    [Storable]
[8962]115    public string OptimizerName {
116      get { return optimizerName; }
[8738]117      set {
[8962]118        if (value != optimizerName && !string.IsNullOrEmpty(value)) {
119          optimizerName = value;
120          OnOptimizerNameChanged();
[8738]121        }
122      }
123    }
124
[8967]125    // BackwardsCompatibility3.3
126    #region Backwards compatible code, remove with 3.4
[16796]127    [Storable(OldName = "AlgorithmName")]
[8962]128    private string AlgorithmName {
129      set { optimizerName = value; }
130    }
[8967]131    #endregion
[8962]132
[4888]133    [StorableHook(HookType.AfterDeserialization)]
134    private void AfterDeserialization() {
135      if (constraints == null) constraints = new RunCollectionConstraintCollection();
[6693]136      if (modifiers == null) modifiers = new CheckedItemList<IRunCollectionModifier>();
[4888]137      RegisterConstraintsEvents();
138      RegisterConstraintEvents(constraints);
[12022]139
140      foreach (var run in this) {
141        RegisterRunParametersEvents(run);
142        RegisterRunResultsEvents(run);
143      }
[4888]144      UpdateFiltering(true);
145    }
146
147    public override IDeepCloneable Clone(Cloner cloner) {
148      return new RunCollection(this, cloner);
149    }
150
151    public event EventHandler UpdateOfRunsInProgressChanged;
152    protected virtual void OnUpdateOfRunsInProgressChanged() {
153      var handler = UpdateOfRunsInProgressChanged;
154      if (handler != null) handler(this, EventArgs.Empty);
155    }
156
[8962]157    public event EventHandler OptimizerNameChanged;
158    protected virtual void OnOptimizerNameChanged() {
159      var handler = OptimizerNameChanged;
[8738]160      if (handler != null) handler(this, EventArgs.Empty);
161    }
162
[3329]163    protected override void OnCollectionReset(IEnumerable<IRun> items, IEnumerable<IRun> oldItems) {
164      parameterNames.Clear();
165      resultNames.Clear();
[7798]166      dataTypes.Clear();
[3329]167      foreach (IRun run in items) {
168        foreach (KeyValuePair<string, IItem> parameter in run.Parameters)
169          AddParameter(parameter.Key, parameter.Value);
170        foreach (KeyValuePair<string, IItem> result in run.Results)
171          AddResult(result.Key, result.Value);
[11344]172        run.PropertyChanged += RunOnPropertyChanged;
173        RegisterRunParametersEvents(run);
174        RegisterRunResultsEvents(run);
[3329]175      }
[11344]176      foreach (IRun run in oldItems) {
177        run.PropertyChanged -= RunOnPropertyChanged;
178        DeregisterRunParametersEvents(run);
179        DeregisterRunResultsEvents(run);
180      }
[4200]181      columnNameCache = null;
[5150]182      OnColumnsChanged();
[3329]183      OnColumnNamesChanged();
[4200]184      rowNamesCache = null;
[4518]185      base.OnCollectionReset(items, oldItems);
[5150]186      OnRowsChanged();
[3329]187      OnRowNamesChanged();
[4518]188      OnReset();
189      UpdateFiltering(false);
[3329]190    }
191    protected override void OnItemsAdded(IEnumerable<IRun> items) {
[5150]192      bool columnsChanged = false;
[3329]193      foreach (IRun run in items) {
194        foreach (KeyValuePair<string, IItem> parameter in run.Parameters)
[5150]195          columnsChanged |= AddParameter(parameter.Key, parameter.Value);
[3329]196        foreach (KeyValuePair<string, IItem> result in run.Results)
[5150]197          columnsChanged |= AddResult(result.Key, result.Value);
[11344]198        run.PropertyChanged += RunOnPropertyChanged;
199        RegisterRunParametersEvents(run);
200        RegisterRunResultsEvents(run);
[3329]201      }
[5150]202      if (columnsChanged) columnNameCache = null;
[4200]203      rowNamesCache = null;
[4518]204      base.OnItemsAdded(items);
[4707]205      OnReset();
[5150]206      OnRowsChanged();
[3329]207      OnRowNamesChanged();
[5150]208      if (columnsChanged) {
209        OnColumnsChanged();
210        OnColumnNamesChanged();
211      }
[4518]212      UpdateFiltering(false);
[3329]213    }
214    protected override void OnItemsRemoved(IEnumerable<IRun> items) {
[5150]215      bool columnsChanged = false;
[3329]216      foreach (IRun run in items) {
217        foreach (string parameterName in run.Parameters.Keys)
[5150]218          columnsChanged |= RemoveParameterName(parameterName);
[3329]219        foreach (string resultName in run.Results.Keys)
[5150]220          columnsChanged |= RemoveResultName(resultName);
[11344]221        run.PropertyChanged -= RunOnPropertyChanged;
222        DeregisterRunParametersEvents(run);
223        DeregisterRunResultsEvents(run);
[3329]224      }
[5150]225      if (columnsChanged) columnNameCache = null;
[4200]226      rowNamesCache = null;
[4518]227      base.OnItemsRemoved(items);
[4707]228      OnReset();
[5152]229      OnRowsChanged();
[3329]230      OnRowNamesChanged();
[5150]231      if (columnsChanged) {
232        OnColumnsChanged();
233        OnColumnNamesChanged();
234      }
[3329]235    }
236
[11344]237    private void RunOnPropertyChanged(object sender, PropertyChangedEventArgs e) {
238      if (e.PropertyName == "Parameters") {
239        RegisterRunParametersEvents((IRun)sender);
240      } else if (e.PropertyName == "Results") {
241        RegisterRunResultsEvents((IRun)sender);
242      }
243    }
244
245    private void RegisterRunParametersEvents(IRun run) {
246      IObservableDictionary<string, IItem> dict = run.Parameters;
247      dict.ItemsAdded += RunOnParameterChanged;
[11345]248      dict.ItemsRemoved += RunOnParameterRemoved;
[11344]249      dict.ItemsReplaced += RunOnParameterChanged;
250      dict.CollectionReset += RunOnParameterChanged;
251    }
252
253    private void RegisterRunResultsEvents(IRun run) {
254      IObservableDictionary<string, IItem> dict = run.Results;
255      dict.ItemsAdded += RunOnResultChanged;
[11345]256      dict.ItemsRemoved += RunOnResultRemoved;
[11344]257      dict.ItemsReplaced += RunOnResultChanged;
258      dict.CollectionReset += RunOnResultChanged;
259    }
260
261    private void DeregisterRunParametersEvents(IRun run) {
262      IObservableDictionary<string, IItem> dict = run.Parameters;
263      dict.ItemsAdded -= RunOnParameterChanged;
[11345]264      dict.ItemsRemoved -= RunOnParameterRemoved;
[11344]265      dict.ItemsReplaced -= RunOnParameterChanged;
266      dict.CollectionReset -= RunOnParameterChanged;
267    }
268
269    private void DeregisterRunResultsEvents(IRun run) {
270      IObservableDictionary<string, IItem> dict = run.Results;
271      dict.ItemsAdded -= RunOnResultChanged;
[11345]272      dict.ItemsRemoved -= RunOnResultRemoved;
[11344]273      dict.ItemsReplaced -= RunOnResultChanged;
274      dict.CollectionReset -= RunOnResultChanged;
275    }
276
277    private void RunOnParameterChanged(object sender, CollectionItemsChangedEventArgs<KeyValuePair<string, IItem>> e) {
278      bool columnsChanged = false;
279      foreach (var param in e.Items)
280        columnsChanged |= AddParameter(param.Key, param.Value);
281      foreach (var param in e.OldItems)
282        columnsChanged |= RemoveParameterName(param.Key);
283      if (columnsChanged) columnNameCache = null;
284      OnReset();
285      if (columnsChanged) {
286        OnColumnsChanged();
287        OnColumnNamesChanged();
288      }
289    }
290
[11345]291    private void RunOnParameterRemoved(object sender, CollectionItemsChangedEventArgs<KeyValuePair<string, IItem>> e) {
292      bool columnsChanged = false;
293      foreach (var param in e.Items)
294        columnsChanged |= RemoveParameterName(param.Key);
295      if (columnsChanged) columnNameCache = null;
296      OnReset();
297      if (columnsChanged) {
298        OnColumnsChanged();
299        OnColumnNamesChanged();
300      }
301    }
302
[11344]303    private void RunOnResultChanged(object sender, CollectionItemsChangedEventArgs<KeyValuePair<string, IItem>> e) {
304      bool columnsChanged = false;
305      foreach (var result in e.Items)
306        columnsChanged |= AddResult(result.Key, result.Value);
307      foreach (var result in e.OldItems)
308        columnsChanged |= RemoveResultName(result.Key);
309      if (columnsChanged) columnNameCache = null;
310      OnReset();
311      if (columnsChanged) {
312        OnColumnsChanged();
313        OnColumnNamesChanged();
314      }
315    }
316
[11345]317    private void RunOnResultRemoved(object sender, CollectionItemsChangedEventArgs<KeyValuePair<string, IItem>> e) {
318      bool columnsChanged = false;
319      foreach (var result in e.Items)
320        columnsChanged |= RemoveResultName(result.Key);
321      if (columnsChanged) columnNameCache = null;
322      OnReset();
323      if (columnsChanged) {
324        OnColumnsChanged();
325        OnColumnNamesChanged();
326      }
327    }
328
[3329]329    private bool AddParameter(string name, IItem value) {
330      if (value == null)
331        return false;
[3441]332      if (!parameterNames.Contains(name)) {
[3329]333        parameterNames.Add(name);
[3614]334        dataTypes[name] = new HashSet<Type>();
335        dataTypes[name].Add(value.GetType());
[3329]336        return true;
337      }
[3614]338      dataTypes[name].Add(value.GetType());
[3329]339      return false;
340    }
341    private bool AddResult(string name, IItem value) {
342      if (value == null)
343        return false;
[3441]344      if (!resultNames.Contains(name)) {
[3329]345        resultNames.Add(name);
[3614]346        dataTypes[name] = new HashSet<Type>();
347        dataTypes[name].Add(value.GetType());
[3329]348        return true;
349      }
[3614]350      dataTypes[name].Add(value.GetType());
[3329]351      return false;
352    }
353    private bool RemoveParameterName(string name) {
354      if (!list.Any(x => x.Parameters.ContainsKey(name))) {
355        parameterNames.Remove(name);
356        return true;
357      }
358      return false;
359    }
360    private bool RemoveResultName(string name) {
361      if (!list.Any(x => x.Results.ContainsKey(name))) {
362        resultNames.Remove(name);
363        return true;
364      }
365      return false;
366    }
367
[3447]368    public IItem GetValue(int rowIndex, int columnIndex) {
369      IRun run = this.list[rowIndex];
[3492]370      return GetValue(run, columnIndex);
371    }
372
373    public IItem GetValue(IRun run, int columnIndex) {
[3717]374      string name = ((IStringConvertibleMatrix)this).ColumnNames.ElementAt(columnIndex);
375      return GetValue(run, name);
376    }
377
378    public IItem GetValue(IRun run, string columnName) {
[3447]379      IItem value = null;
[3767]380      if (run.Parameters.ContainsKey(columnName))
381        value = run.Parameters[columnName];
382      else if (run.Results.ContainsKey(columnName))
383        value = run.Results[columnName];
[3447]384      return value;
385    }
386
[3329]387    #region IStringConvertibleMatrix Members
[3347]388    [Storable]
[3329]389    private List<string> parameterNames;
[3492]390    public IEnumerable<string> ParameterNames {
391      get { return this.parameterNames; }
392    }
[3347]393    [Storable]
[3329]394    private List<string> resultNames;
[3492]395    public IEnumerable<string> ResultNames {
396      get { return this.resultNames; }
397    }
[3447]398    int IStringConvertibleMatrix.Rows {
[3329]399      get { return this.Count; }
[3447]400      set { throw new NotSupportedException(); }
[3329]401    }
[3447]402    int IStringConvertibleMatrix.Columns {
[3329]403      get { return parameterNames.Count + resultNames.Count; }
404      set { throw new NotSupportedException(); }
405    }
[4200]406    private List<string> columnNameCache;
[3447]407    IEnumerable<string> IStringConvertibleMatrix.ColumnNames {
[3329]408      get {
[4200]409        if (columnNameCache == null) {
410          columnNameCache = new List<string>(parameterNames);
411          columnNameCache.AddRange(resultNames);
412          columnNameCache.Sort();
413        }
414        return columnNameCache;
[3329]415      }
416      set { throw new NotSupportedException(); }
417    }
[4200]418    private List<string> rowNamesCache;
[3447]419    IEnumerable<string> IStringConvertibleMatrix.RowNames {
[4200]420      get {
421        if (rowNamesCache == null)
422          rowNamesCache = list.Select(x => x.Name).ToList();
423        return rowNamesCache;
424      }
[3329]425      set { throw new NotSupportedException(); }
426    }
[3447]427    bool IStringConvertibleMatrix.SortableView {
[3329]428      get { return true; }
429      set { throw new NotSupportedException(); }
430    }
[3447]431    bool IStringConvertibleMatrix.ReadOnly {
432      get { return true; }
[3430]433    }
[3329]434
[3447]435    string IStringConvertibleMatrix.GetValue(int rowIndex, int columnIndex) {
436      IItem value = GetValue(rowIndex, columnIndex);
437      if (value == null)
438        return string.Empty;
439      return value.ToString();
[3329]440    }
441
442    public event EventHandler<EventArgs<int, int>> ItemChanged;
443    protected virtual void OnItemChanged(int rowIndex, int columnIndex) {
[4722]444      EventHandler<EventArgs<int, int>> handler = ItemChanged;
445      if (handler != null) handler(this, new EventArgs<int, int>(rowIndex, columnIndex));
[3329]446    }
447    public event EventHandler Reset;
448    protected virtual void OnReset() {
[4722]449      EventHandler handler = Reset;
450      if (handler != null) handler(this, EventArgs.Empty);
[3329]451    }
[5150]452    public event EventHandler ColumnsChanged;
453    protected virtual void OnColumnsChanged() {
454      var handler = ColumnsChanged;
455      if (handler != null) handler(this, EventArgs.Empty);
456    }
457    public event EventHandler RowsChanged;
458    protected virtual void OnRowsChanged() {
459      var handler = RowsChanged;
460      if (handler != null) handler(this, EventArgs.Empty);
461    }
[3329]462    public event EventHandler ColumnNamesChanged;
463    protected virtual void OnColumnNamesChanged() {
464      EventHandler handler = ColumnNamesChanged;
[4722]465      if (handler != null) handler(this, EventArgs.Empty);
[3329]466    }
467    public event EventHandler RowNamesChanged;
468    protected virtual void OnRowNamesChanged() {
469      EventHandler handler = RowNamesChanged;
[4722]470      if (handler != null) handler(this, EventArgs.Empty);
[3329]471    }
472    public event EventHandler SortableViewChanged;
[3333]473    protected virtual void OnSortableViewChanged() {
474      EventHandler handler = SortableViewChanged;
[4722]475      if (handler != null) handler(this, EventArgs.Empty);
[3333]476    }
477
[3329]478    public bool Validate(string value, out string errorMessage) { throw new NotSupportedException(); }
479    public bool SetValue(string value, int rowIndex, int columnIndex) { throw new NotSupportedException(); }
480    #endregion
[3614]481
[4888]482    #region Filtering
[3632]483    private void UpdateFiltering(bool reset) {
484      if (reset)
485        list.ForEach(r => r.Visible = true);
[3614]486      foreach (IRunCollectionConstraint constraint in this.constraints)
487        constraint.Check();
488    }
489
[4164]490    private void RegisterConstraintsEvents() {
491      constraints.ItemsAdded += new CollectionItemsChangedEventHandler<IRunCollectionConstraint>(Constraints_ItemsAdded);
492      constraints.ItemsRemoved += new CollectionItemsChangedEventHandler<IRunCollectionConstraint>(Constraints_ItemsRemoved);
493      constraints.CollectionReset += new CollectionItemsChangedEventHandler<IRunCollectionConstraint>(Constraints_CollectionReset);
494    }
495
[12022]496    private void RegisterConstraintEvents(IEnumerable<IRunCollectionConstraint> constraints) {
[3614]497      foreach (IRunCollectionConstraint constraint in constraints) {
498        constraint.ActiveChanged += new EventHandler(Constraint_ActiveChanged);
499        constraint.ConstrainedValueChanged += new EventHandler(Constraint_ConstrainedValueChanged);
500        constraint.ConstraintOperationChanged += new EventHandler(Constraint_ConstraintOperationChanged);
501        constraint.ConstraintDataChanged += new EventHandler(Constraint_ConstraintDataChanged);
502      }
503    }
[12022]504    private void DeregisterConstraintEvents(IEnumerable<IRunCollectionConstraint> constraints) {
[3614]505      foreach (IRunCollectionConstraint constraint in constraints) {
506        constraint.ActiveChanged -= new EventHandler(Constraint_ActiveChanged);
507        constraint.ConstrainedValueChanged -= new EventHandler(Constraint_ConstrainedValueChanged);
508        constraint.ConstraintOperationChanged -= new EventHandler(Constraint_ConstraintOperationChanged);
509        constraint.ConstraintDataChanged -= new EventHandler(Constraint_ConstraintDataChanged);
510      }
511    }
512
513    protected virtual void Constraints_CollectionReset(object sender, CollectionItemsChangedEventArgs<IRunCollectionConstraint> e) {
514      DeregisterConstraintEvents(e.OldItems);
515      RegisterConstraintEvents(e.Items);
[3632]516      this.UpdateFiltering(true);
[3614]517    }
518    protected virtual void Constraints_ItemsAdded(object sender, CollectionItemsChangedEventArgs<IRunCollectionConstraint> e) {
519      RegisterConstraintEvents(e.Items);
520      foreach (IRunCollectionConstraint constraint in e.Items)
521        constraint.ConstrainedValue = this;
[3632]522      this.UpdateFiltering(false);
[3614]523    }
524    protected virtual void Constraints_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<IRunCollectionConstraint> e) {
525      DeregisterConstraintEvents(e.Items);
[3632]526      this.UpdateFiltering(true);
[3614]527    }
528    protected virtual void Constraint_ActiveChanged(object sender, EventArgs e) {
[3632]529      IRunCollectionConstraint constraint = (IRunCollectionConstraint)sender;
530      this.UpdateFiltering(!constraint.Active);
[3614]531    }
532    protected virtual void Constraint_ConstrainedValueChanged(object sender, EventArgs e) {
533      //mkommend: this method is intentionally left empty, because the constrainedValue is set in the ItemsAdded method
534    }
535    protected virtual void Constraint_ConstraintOperationChanged(object sender, EventArgs e) {
[3632]536      IRunCollectionConstraint constraint = (IRunCollectionConstraint)sender;
[13181]537      if (constraint.Active) {
[13198]538        var oldUpdateRuns = UpdateOfRunsInProgress;
[13181]539        try {
540          UpdateOfRunsInProgress = true;
541          UpdateFiltering(true);
[13198]542        } finally { UpdateOfRunsInProgress = oldUpdateRuns; }
[13181]543      }
[3614]544    }
545    protected virtual void Constraint_ConstraintDataChanged(object sender, EventArgs e) {
[3632]546      IRunCollectionConstraint constraint = (IRunCollectionConstraint)sender;
[13181]547      if (constraint.Active) {
[13198]548        var oldUpdateRuns = UpdateOfRunsInProgress;
[13181]549        try {
550          UpdateOfRunsInProgress = true;
551          UpdateFiltering(true);
[13198]552        } finally { UpdateOfRunsInProgress = oldUpdateRuns; }
[13181]553      }
[3614]554    }
555    #endregion
[6693]556
557    #region Modification
558    public void Modify() {
559      var runs = this.ToList();
560      var selectedRuns = runs.Where(r => r.Visible).ToList();
561      int nSelected = selectedRuns.Count;
562      if (nSelected > 0) {
563        foreach (var modifier in Modifiers.CheckedItems)
564          modifier.Value.Modify(selectedRuns);
565        if (nSelected != selectedRuns.Count || HaveDifferentOrder(selectedRuns, runs.Where(r => r.Visible))) {
566          Clear();
567          AddRange(ReplaceVisibleRuns(runs, selectedRuns));
568        } else if (runs.Count > 0) {
569          OnCollectionReset(this, runs);
570        }
571      }
572    }
573
574    private static IEnumerable<IRun> ReplaceVisibleRuns(IEnumerable<IRun> runs, IEnumerable<IRun> visibleRuns) {
575      var newRuns = new List<IRun>();
576      var runIt = runs.GetEnumerator();
577      var visibleRunIt = visibleRuns.GetEnumerator();
578      while (runIt.MoveNext()) {
579        if (runIt.Current != null && !runIt.Current.Visible)
580          newRuns.Add(runIt.Current);
581        else if (visibleRunIt.MoveNext())
582          newRuns.Add(visibleRunIt.Current);
583      }
584      while (visibleRunIt.MoveNext())
585        newRuns.Add(visibleRunIt.Current);
586      return newRuns;
587    }
588
589    private static bool HaveDifferentOrder(IEnumerable<IRun> l1, IEnumerable<IRun> l2) {
590      return l1.Zip(l2, (r1, r2) => r1 != r2).Any();
591    }
592    #endregion
[3260]593  }
594}
Note: See TracBrowser for help on using the repository browser.