Free cookie consent management tool by TermsFeed Policy Generator

source: stable/HeuristicLab.Optimization/3.3/RunCollection.cs @ 16075

Last change on this file since 16075 was 15584, checked in by swagner, 7 years ago

#2640: Updated year of copyrights in license headers on stable

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