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 @ 2768

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

added solution folders and sources for the netron library (ticket #867)

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