Free cookie consent management tool by TermsFeed Policy Generator

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

Last change on this file since 15682 was 4068, checked in by swagner, 14 years ago

Sorted usings and removed unused usings in entire solution (#1094)

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