Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.Netron/3.0.2672.12446/Netron.Diagramming.Core-3.0.2672.12446/Utils/Selection.cs @ 2909

Last change on this file since 2909 was 2898, checked in by mkommend, 14 years ago

added details view for parameters (ticket #867)

File size: 14.1 KB
Line 
1using System;
2using System.Collections.Generic;
3using System.Collections;
4using System.Text;
5using System.Drawing;
6using System.Drawing.Drawing2D;
7namespace Netron.Diagramming.Core {
8  /// <summary>
9  /// This static class collects functions related to bundle selection
10  /// </summary>
11  public class Selection {
12
13    public Selection(IController controller, IModel model) {
14      this.mController = controller;
15      this.mModel = model;
16    }
17
18    #region Events
19    public event EventHandler OnNewSelection;
20    #endregion
21
22    #region Fields
23    // ------------------------------------------------------------------
24    /// <summary>
25    /// Specifies the way entities are selected.
26    /// </summary>
27    // ------------------------------------------------------------------
28    private SelectionTypes mSelectionType = SelectionTypes.Partial;
29
30    // ------------------------------------------------------------------
31    /// <summary>
32    /// The selected entities.
33    /// </summary>
34    // ------------------------------------------------------------------
35    private CollectionBase<IDiagramEntity> mSelection =
36        new CollectionBase<IDiagramEntity>();
37
38    // ------------------------------------------------------------------
39    /// <summary>
40    /// A pointer to the model.
41    /// </summary>
42    // ------------------------------------------------------------------
43    private IModel mModel;
44    private IController mController;
45
46    // ------------------------------------------------------------------
47    /// <summary>
48    /// A pointer to a selected connector.
49    /// </summary>
50    // ------------------------------------------------------------------
51    private IConnector connector;
52
53    #endregion
54
55    #region Properties
56
57    // ------------------------------------------------------------------
58    /// <summary>
59    /// Gets or sets the connector selected by the user.
60    /// </summary>
61    /// <value>The connector.</value>
62    // ------------------------------------------------------------------
63    public IConnector Connector {
64      get {
65        return connector;
66      }
67      set {
68        connector = value;
69      }
70    }
71
72    // ------------------------------------------------------------------
73    /// <summary>
74    /// Gets the Model we're attached to.
75    /// </summary>
76    // ------------------------------------------------------------------
77    public IModel Model {
78      get {
79        return mModel;
80      }
81    }
82
83    public IController Controller {
84      get {
85        return mController;
86      }
87    }
88
89    // ------------------------------------------------------------------
90    /// <summary>
91    /// Gets or sets the selected items.
92    /// </summary>
93    /// <value>The selected items.</value>
94    // ------------------------------------------------------------------
95    public CollectionBase<IDiagramEntity> SelectedItems {
96      get {
97        return mSelection;
98      }
99      internal set {
100        if (value == null || value.Count == 0)
101          return;
102        //clear the current selection
103        Clear();
104
105        mSelection = value;
106        foreach (IDiagramEntity entity in value) {
107          if (entity.Group != null)
108            entity.Group.IsSelected = true;
109          else
110            entity.IsSelected = true;
111        }
112      }
113    }
114
115    // ------------------------------------------------------------------
116    /// <summary>
117    /// Gets the selected items but in flat form, i.e. the entities
118    /// inside an <see cref="IGroup"/> are collected.
119    /// </summary>
120    // ------------------------------------------------------------------
121    public CollectionBase<IDiagramEntity> FlattenedSelectionItems {
122      get {
123        CollectionBase<IDiagramEntity> flatList =
124            new CollectionBase<IDiagramEntity>();
125        foreach (IDiagramEntity entity in mSelection) {
126          if (entity is IGroup)
127            Utils.TraverseCollect(entity as IGroup, ref flatList);
128          else
129            flatList.Add(entity);
130        }
131        return flatList;
132      }
133    }
134
135    #endregion
136
137    #region Methods
138
139    // ------------------------------------------------------------------
140    /// <summary>
141    /// Creates a Bitmap from the selected entities.  If no entities are
142    /// selected, then 'null' is returned.
143    /// </summary>
144    /// <returns>Bitmap</returns>
145    // ------------------------------------------------------------------
146    public Bitmap ToBitmap() {
147      if (SelectedItems.Count <= 0) {
148        return null;
149      }
150
151      Graphics g = mController.View.Graphics;
152      g.Transform = mController.View.ViewMatrix;
153      g.SmoothingMode = SmoothingMode.HighQuality;
154      Bundle bundle = new Bundle(SelectedItems.Copy());
155      return ImageExporter.FromBundle(bundle, g);
156    }
157
158    public IConnector FindConnector(Predicate<IConnector> predicate) {
159      IConnection con;
160      IShape sh;
161
162      foreach (IDiagramEntity entity in Model.Paintables) {
163        if (typeof(IShape).IsInstanceOfType(entity)) {
164          sh = entity as IShape;
165          foreach (IConnector cn in sh.Connectors) {
166            if (predicate(cn))
167              return cn;
168          }
169        } else if (typeof(IConnection).IsInstanceOfType(entity)) {
170          con = entity as IConnection;
171          if (predicate(con.From))
172            return con.From;
173          if (predicate(con.To))
174            return con.To;
175        }
176      }
177      return null;
178    }
179
180    /// <summary>
181    /// Finds the first connector with the highest z-order under the given point
182    /// </summary>
183    /// <returns></returns>
184    public IConnector FindShapeConnector(Point surfacePoint) {
185
186
187      IShape sh;
188
189      foreach (IDiagramEntity entity in Model.Paintables) {
190        if (typeof(IShape).IsInstanceOfType(entity)) {
191          sh = entity as IShape;
192          foreach (IConnector cn in sh.Connectors) {
193            if (cn.Hit(surfacePoint))
194              return cn;
195          }
196        }
197      }
198      return null;
199    }
200
201    public IConnector FindConnectorAt(Point surfacePoint) {
202      IConnection con;
203      IShape sh;
204
205      foreach (IDiagramEntity entity in Model.Paintables) {
206        if (entity is IShape) {
207          sh = entity as IShape;
208          foreach (IConnector cn in sh.Connectors) {
209            if (cn.Hit(surfacePoint))
210              return cn;
211          }
212        } else if (entity is IConnection) {
213          con = entity as IConnection;
214          if (con.From.Hit(surfacePoint))
215            return con.From;
216          if (con.To.Hit(surfacePoint))
217            return con.To;
218        }
219      }
220      return null;
221    }
222    /// <summary>
223    /// Collects the shapes at the given (transformed surface) location.
224    /// The shapes selected in this way are available
225    /// </summary>
226    /// <param name="surfacePoint">The surface point.</param>
227    public void CollectEntitiesAt(
228        Point surfacePoint,
229        bool clearSelectionFirst) {
230      if (surfacePoint == Point.Empty)
231        return;
232      if (mModel == null)
233        return;
234
235      // Only change the current selection if the mouse did not hit an
236      // already selected element and the element is not a group.  This
237      // allows drilling down into group's children.
238      if (mSelection.Count > 0) {
239        foreach (IDiagramEntity entity in mSelection) {
240          if ((entity.Hit(surfacePoint)) &&
241              ((entity is IGroup) == false)) {
242            return;
243          }
244        }
245      }
246
247      // Clear the current selection only if we're supposed to.
248      if (clearSelectionFirst) {
249        Clear();
250      }
251
252      IConnection con;
253      IShape sh;
254
255      //we use the paintables here rather than traversing the scene-graph because only
256      //visible things can be collected
257      //We traverse the paintables from top to bottom since the highest z-order
258      //is at the top of the stack.
259
260      for (int k = Model.Paintables.Count - 1; k >= 0; k--) {
261        IDiagramEntity entity = Model.Paintables[k];
262
263        #region we give priority to the connector selection
264        if (typeof(IConnection).IsInstanceOfType(entity)) {
265          con = entity as IConnection;
266          if (con.From.Hit(surfacePoint)) {
267            connector = con.From;
268            connector.IsSelected = true;
269            this.RaiseOnNewSelection();
270            Invalidate();
271            return;
272          }
273          if (con.To.Hit(surfacePoint)) {
274            connector = con.To;
275            connector.IsSelected = true;
276            this.RaiseOnNewSelection();
277            Invalidate();
278            return;
279          }
280        } else if (entity is IGroup) {
281          //should I care about the connectors at this point...?
282        } else if (entity is IShape) {
283          sh = entity as IShape;
284          foreach (IConnector cn in sh.Connectors) {
285            //if there are connectors attached to the shape connector, the attached ones should be picked up and not the one of the shape
286            if (cn.Hit(surfacePoint) && cn.AttachedConnectors.Count == 0) {
287              connector = cn;
288              connector.IsSelected = true;
289              this.RaiseOnNewSelection();
290              Invalidate();//this will invalidate only the selected connector
291              return; //we hit a connector and quit the selection. If the user intended to select the entity it had to be away from the connector!
292            }
293          }
294        }
295
296        #endregion
297
298        #region no connector was hit, maybe the entity itself
299        if (entity.Hit(surfacePoint)) {
300          SelectEntity(entity, surfacePoint);
301          break;
302        }
303        #endregion
304      }
305      RaiseOnNewSelection();
306
307      // Using a full invalidate is rather expensive, so we'll only
308      // refresh the current selection.
309      //Controller.View.Invalidate();
310      Invalidate();
311    }
312
313    internal void SelectEntity(IDiagramEntity entity, Point surfacePoint) {
314      // Groups are treated specially because we can drill-down
315      // into the group.  The process of drilling is the first
316      // mouse hit will select the group.  The second mouse hit
317      // will select a child, if there's a child at that point.
318      if (entity is IGroup) {
319        if (entity.IsSelected == false) {
320          entity.IsSelected = true;
321          mSelection.Add(entity);
322        } else {
323          IGroup group = entity as IGroup;
324          for (int j = group.Entities.Count - 1; j >= 0; j--) {
325            IDiagramEntity child = group.Entities[j];
326            if (child.Hit(surfacePoint)) {
327              // Repeat the process because what if this
328              // child is too a group!
329              SelectEntity(child, surfacePoint);
330              group.IsSelected = false;
331              if (mSelection.Contains(group)) {
332                mSelection.Remove(group);
333              }
334              break;
335            }
336          }
337        }
338      }
339        //else if (entity.Group != null)
340        //{
341        //    //entity.Group.IsSelected = true;
342        //    //mSelection.Add(entity.Group);
343        //}
344      else {
345        entity.IsSelected = true;
346        mSelection.Add(entity);
347      }
348    }
349
350    private void RaiseOnNewSelection() {
351      if (OnNewSelection != null)
352        OnNewSelection(null, EventArgs.Empty);
353    }
354    /// <summary>
355    /// Invalidates the current selection (either a connector or a set of entities).
356    /// </summary>
357    public void Invalidate() {
358      if (connector != null)
359        connector.Invalidate();
360
361      foreach (IDiagramEntity entity in mSelection) {
362        entity.Invalidate();
363      }
364    }
365    /// <summary>
366    /// Collects the entities inside the given rectangle.
367    /// </summary>
368    /// <param name="surfaceRectangle">The surface rectangle.</param>
369    public void CollectEntitiesInside(Rectangle surfaceRectangle) {
370      if (surfaceRectangle == Rectangle.Empty)
371        return;
372      this.Clear();
373      foreach (IDiagramEntity entity in Model.Paintables) {
374        //if the entity is part of a group we have to look at the bigger picture
375        if (mSelectionType == SelectionTypes.Inclusion) {
376          if (entity.Group != null) {
377            //the rectangle must contain the whole group
378            if (surfaceRectangle.Contains(entity.Group.Rectangle)) {
379              //add the group if not already present via another group member
380              if (!mSelection.Contains(entity.Group))
381                mSelection.Add(entity.Group);
382              continue;
383            }
384          } else {
385            if (surfaceRectangle.Contains(entity.Rectangle)) {
386
387              mSelection.Add(entity);
388              entity.IsSelected = true;
389            }
390          }
391        } else //the selection requires only partial overlap with the rectangle
392                {
393          if (entity.Group != null) {
394            if (surfaceRectangle.IntersectsWith(entity.Group.Rectangle)) {
395              if (!mSelection.Contains(entity.Group))
396                mSelection.Add(entity.Group);
397              continue;
398            }
399          } else {
400            if (surfaceRectangle.IntersectsWith(entity.Rectangle)) {
401              if (!mSelection.Contains(entity))//it could be a group which got already selected by one of its children
402                            {
403                mSelection.Add(entity);
404                entity.IsSelected = true;
405              }
406            }
407          }
408        }
409
410
411
412      }
413      RaiseOnNewSelection();
414
415    }
416    /// <summary>
417    /// Clears the current selection
418    /// </summary>
419    public void Clear() {
420      if (connector != null) {
421        connector.IsSelected = false;
422        connector = null;
423      }
424
425      if (mController == null || mModel == null)
426        return;
427      //deselect the current ones
428      foreach (IDiagramEntity entity in SelectedItems) {
429        entity.IsSelected = false;
430      }
431      //forget the current state
432      mSelection.Clear();
433      if (Controller.View != null)
434        Controller.View.HideTracker();
435    }
436
437
438    #endregion
439  }
440}
Note: See TracBrowser for help on using the repository browser.