Free cookie consent management tool by TermsFeed Policy Generator

source: branches/DataAnalysis Refactoring/HeuristicLab.ExtLibs/HeuristicLab.Netron/3.0.2672.12446/Netron.Diagramming.Core-3.0.2672.12446/Core/ControllerBase.cs @ 5796

Last change on this file since 5796 was 5796, checked in by mkommend, 13 years ago

#1418: Merged trunk changes into branch.

File size: 51.1 KB
Line 
1using System;
2using System.Drawing;
3using System.Windows.Forms;
4namespace Netron.Diagramming.Core {
5  // ----------------------------------------------------------------------
6  /// <summary>
7  /// Abstract base implementation of the <see cref="IController"/>
8  /// interface.
9  /// </summary>
10  // ----------------------------------------------------------------------
11  public abstract class ControllerBase : IUndoSupport, IController {
12    #region Events
13
14    // ------------------------------------------------------------------
15    /// <summary>
16    /// Occurs when the context menu is shown.
17    /// </summary>
18    // ------------------------------------------------------------------
19    public event EventHandler<EntityMenuEventArgs> OnShowContextMenu;
20
21    // ------------------------------------------------------------------
22    /// <summary>
23    /// Occurs when a tool is asked to be deactivated.
24    /// </summary>
25    // ------------------------------------------------------------------
26    public event EventHandler<ToolEventArgs> OnToolDeactivate;
27
28    // ------------------------------------------------------------------
29    /// <summary>
30    /// Occurs when a tool is asked to be activated.
31    /// </summary>
32    // ------------------------------------------------------------------
33    public event EventHandler<ToolEventArgs> OnToolActivate;
34
35    // ------------------------------------------------------------------
36    /// <summary>
37    /// Occurs when the history has changed in the undo/redo mechanism.
38    /// </summary>
39    // ------------------------------------------------------------------
40    public event EventHandler<HistoryChangeEventArgs> OnHistoryChange;
41
42    // ------------------------------------------------------------------
43    /// <summary>
44    /// Occurs when the something got selected and the properties of it
45    /// can/should be shown.
46    /// </summary>
47    // ------------------------------------------------------------------
48    public event EventHandler<SelectionEventArgs> OnShowSelectionProperties;
49
50    // ------------------------------------------------------------------
51    /// <summary>
52    /// Occurs when an entity is added.
53    /// <remarks>This event usually is bubbled from one of the
54    /// layers.</remarks>
55    /// </summary>
56    // ------------------------------------------------------------------
57    public event EventHandler<EntityEventArgs> OnEntityAdded;
58
59    // ------------------------------------------------------------------
60    /// <summary>
61    /// Occurs when an entity is removed.
62    /// <remarks>This event usually is bubbled from one of the
63    /// layers.</remarks>
64    /// </summary>
65    // ------------------------------------------------------------------
66    public event EventHandler<EntityEventArgs> OnEntityRemoved;
67
68    // ------------------------------------------------------------------
69    /// <summary>
70    /// Occurs when the controller receives a mouse-down notification of
71    /// the surface. This event is raised before the
72    /// event is broadcasted down to the tools.
73    /// </summary>
74    // ------------------------------------------------------------------
75    public event EventHandler<MouseEventArgs> OnMouseDown;
76
77    // ------------------------------------------------------------------
78    /// <summary>
79    /// Occurs when the Ambience has changed.
80    /// </summary>
81    // ------------------------------------------------------------------
82    public event EventHandler<AmbienceEventArgs> OnAmbienceChanged;
83
84
85    #endregion
86
87    #region Tool Names
88
89    public const string AlignBottomEdgesToolName =
90        "Align Bottom Edges Tool";
91
92    public const string AlignCentersHorizToolName =
93        "Align Centers Horizontally";
94
95    public const string AlignCentersVertToolName =
96        "Align Centers Vertically";
97
98    public const string AlignLeftEdgesToolName =
99        "Align Left Edges Tool";
100
101    public const string AlignRightEdgesToolName =
102        "Align Right Edges Tool";
103
104    public const string AlignTopEdgesToolName =
105        "Align Top Edges Tool";
106
107    public const string ComplexRectangleToolName = "ComplexRectangle Tool";
108    public const string ConnectionToolName = "Connection Tool";
109    public const string ConnectorMoverToolName = "Connector Mover Tool";
110    public const string ContextToolName = "Context Tool";
111    public const string CopyToolName = "Copy Tool";
112    public const string CutToolName = "Cut Tool";
113    public const string DeleteToolName = "Delete Tool";
114    public const string DragDropToolName = "DragDrop Tool";
115    public const string EllipseToolName = "Ellipse Tool";
116    public const string GroupToolName = "Group Tool";
117    public const string HitToolName = "Hit Tool";
118    public const string HoverToolName = "Hover Tool";
119    public const string ImageExportToolName = "Image Export Tool";
120    public const string MoveToolName = "Move Tool";
121    public const string MultiLineToolName = "MultiLine Tool";
122    public const string PanToolName = "Pan Tool";
123    public const string PasteToolName = "Paste Tool";
124    public const string PolygonToolName = "Polygon Tool";
125    public const string RectangleToolName = "Rectangle Tool";
126    public const string ScribbleToolName = "Scribble Tool";
127    public const string SelectionToolName = "Selection Tool";
128    public const string SendBackwardsToolName = "SendBackwards Tool";
129    public const string SendForwardsToolName = "SendForwards Tool";
130    public const string SendToBackToolName = "SendToBack Tool";
131    public const string SendToFrontToolName = "SendToFront Tool";
132    public const string TransformToolName = "Transform Tool";
133    public const string UngroupToolName = "Ungroup Tool";
134    public const string ZoomAreaToolName = "Zoom Area Tool";
135    public const string ZoomInToolName = "Zoom In Tool";
136    public const string ZoomOutToolName = "Zoom Out Tool";
137
138    #endregion
139
140    #region Fields
141
142    private bool eventsEnabled = true;
143    private bool controllerEnabled = true;
144
145    private IModel mModel;
146    private UndoManager mUndoManager;
147    ITool activeTool;
148
149    /// <summary>
150    /// the View field
151    /// </summary>
152    private IView mView;
153    protected CollectionBase<IMouseListener> mouseListeners;
154    protected CollectionBase<IKeyboardListener> keyboardListeners;
155    protected CollectionBase<IDragDropListener> dragdropListeners;
156    private IDiagramControl parentControl;
157    protected CollectionBase<ITool> registeredTools;
158    protected CollectionBase<IActivity> registeredActivity;
159
160    #endregion
161
162    #region Properties
163
164    /// <summary>
165    /// Gets or sets a value indicating whether this <see cref="T:ControllerBase"/> is enabled.
166    /// </summary>
167    /// <value><c>true</c> if enabled; otherwise, <c>false</c>.</value>
168    public bool Enabled {
169      get {
170        return controllerEnabled;
171      }
172      set {
173        controllerEnabled = value;
174      }
175    }
176
177    // ------------------------------------------------------------------
178    /// <summary>
179    /// Gets the currently active tool.  This can be 'null'!!!
180    /// </summary>
181    // ------------------------------------------------------------------
182    public ITool ActiveTool {
183      get {
184        return this.activeTool;
185      }
186    }
187
188    /// <summary>
189    /// Gets or sets the parent control.
190    /// </summary>
191    /// <value>The parent control.</value>
192    public IDiagramControl ParentControl {
193      get { return parentControl; }
194      protected internal set { parentControl = value; }
195    }
196    /// <summary>
197    /// Gets the registered tools.
198    /// </summary>
199    /// <value>The tools.</value>
200    public CollectionBase<ITool> Tools {
201      get { return registeredTools; }
202    }
203
204
205
206    /// <summary>
207    /// Gets the undo manager.
208    /// </summary>
209    /// <value>The undo manager.</value>
210    public UndoManager UndoManager {
211      get {
212        return mUndoManager;
213      }
214
215    }
216
217    /// <summary>
218    /// Gets or sets the model
219    /// </summary>
220    /// <value></value>
221    public IModel Model {
222      get {
223        return mModel;
224      }
225      set {
226        AttachToModel(value);
227      }
228    }
229
230    /// <summary>
231    /// Gets or sets the view.
232    /// </summary>
233    /// <value>The view.</value>
234    public IView View {
235      get {
236        return mView;
237      }
238      set {
239        AttachToView(value);
240      }
241    }
242
243    /// <summary>
244    /// Attaches to the given view.
245    /// </summary>
246    /// <param name="view">The view.</param>
247    private void AttachToView(IView view) {
248      if (view == null)
249        throw new ArgumentNullException();
250
251      mView = view;
252    }
253    #endregion
254
255    #region Constructor
256
257    // ------------------------------------------------------------------
258    /// <summary>
259    /// Default constructor.
260    /// </summary>
261    // ------------------------------------------------------------------
262    protected ControllerBase(IDiagramControl surface) {
263      //doesn't work if you supply a null reference
264      if (surface == null) {
265        throw new NullReferenceException(
266            "The diagram control assigned to the controller " +
267            "cannot be 'null'");
268      }
269
270      //create the undo/redo manager
271      mUndoManager = new UndoManager(15);
272      mUndoManager.OnHistoryChange += new EventHandler(
273          mUndoManager_OnHistoryChange);
274
275      #region Instantiation of listeners
276      mouseListeners = new CollectionBase<IMouseListener>();
277      keyboardListeners = new CollectionBase<IKeyboardListener>();
278      dragdropListeners = new CollectionBase<IDragDropListener>();
279      #endregion
280
281      //keep a reference to the parent control
282      parentControl = surface;
283
284      AttachToSurface(parentControl);
285
286
287
288      //Initialize the colorscheme
289      ArtPalette.Init();
290
291      #region Tools: the registration order matters!
292      /*
293             The order in in which the tools are added matters, at least
294             some of them.
295               * The TransformTool should come before the HitTool and the
296                 MoveTool after the HitTool.
297               * The order of the drawing tools does not matter.
298               * It's also important to remark that the tools do not depend
299                 on the Model.
300             */
301
302      registeredTools = new CollectionBase<ITool>();
303
304      this.AddTool(new TransformTool(TransformToolName));
305
306      this.AddTool(new HitTool(HitToolName));
307
308      this.AddTool(new MoveTool(MoveToolName));
309
310      this.AddTool(new RectangleTool(RectangleToolName));
311
312      this.AddTool(new ComplexRectangleTool(ComplexRectangleToolName));
313
314      this.AddTool(new EllipseTool(EllipseToolName));
315
316      this.AddTool(new SelectionTool(SelectionToolName));
317
318      this.AddTool(new DragDropTool(DragDropToolName));
319
320      this.AddTool(new ConnectionTool(ConnectionToolName));
321
322      this.AddTool(new ConnectorMoverTool(ConnectorMoverToolName));
323
324      this.AddTool(new GroupTool(GroupToolName));
325
326      this.AddTool(new UngroupTool(UngroupToolName));
327
328      this.AddTool(new SendToBackTool(SendToBackToolName));
329
330      this.AddTool(new SendBackwardsTool(SendBackwardsToolName));
331
332      this.AddTool(new SendForwardsTool(SendForwardsToolName));
333
334      this.AddTool(new SendToFrontTool(SendToFrontToolName));
335
336      this.AddTool(new HoverTool(HoverToolName));
337
338      this.AddTool(new ContextTool(ContextToolName));
339
340      this.AddTool(new CopyTool(CopyToolName));
341
342      this.AddTool(new CutTool(CutToolName));
343
344      this.AddTool(new PasteTool(PasteToolName));
345
346      this.AddTool(new DeleteTool(DeleteToolName));
347
348      this.AddTool(new ScribbleTool(ScribbleToolName));
349
350      this.AddTool(new PolygonTool(PolygonToolName));
351
352      this.AddTool(new MultiLineTool(MultiLineToolName));
353
354      this.AddTool(new AlignBottomEdgesTool(AlignBottomEdgesToolName));
355
356      this.AddTool(
357          new AlignCentersHorizontallyTool(AlignCentersHorizToolName));
358
359      this.AddTool(
360          new AlignCentersVerticallyTool(AlignCentersVertToolName));
361
362      this.AddTool(new AlignLeftEdgesTool(AlignLeftEdgesToolName));
363
364      this.AddTool(new AlignRightEdgesTool(AlignRightEdgesToolName));
365
366      this.AddTool(new AlignTopEdgesTool(AlignTopEdgesToolName));
367
368      this.AddTool(new ZoomAreaTool(ZoomAreaToolName));
369
370      this.AddTool(new ZoomInTool(ZoomInToolName));
371
372      this.AddTool(new ZoomOutTool(ZoomOutToolName));
373
374      this.AddTool(new PanTool(PanToolName));
375
376      this.AddTool(new ImageExportTool(ImageExportToolName));
377
378      #endregion
379
380      #region Hotkeys
381      HotKeys keys = new HotKeys(this);
382      this.keyboardListeners.Add(keys);
383      #endregion
384
385      #region Activities
386      // This is in a way a waste of memory; the layouts should not
387      // necessarily be loaded before they are actually requested.
388      // You could register only the (string) names instead.
389      // But for just a few algorithms this is OK and the advantage
390      // of this registration is that one can register actions from
391      // outside the library, in the hosting form for example.
392      registeredActivity = new CollectionBase<IActivity>();
393      AddActivity(new RandomLayout(this));
394      AddActivity(new FruchtermanReingoldLayout(this));
395      AddActivity(new StandardTreeLayout(this));
396      AddActivity(new RadialTreeLayout(this));
397      AddActivity(new BalloonTreeLayout(this));
398      AddActivity(new ForceDirectedLayout(this));
399      #endregion
400    }
401
402    #endregion
403
404    // ------------------------------------------------------------------
405    /// <summary>
406    /// Attaches the given model to the controller.
407    /// </summary>
408    /// <param name="model">IModel</param>
409    // ------------------------------------------------------------------
410    protected virtual void AttachToModel(IModel model) {
411      if (model == null)
412        throw new ArgumentNullException();
413
414      mModel = model;
415      mModel.OnEntityAdded +=
416          new EventHandler<EntityEventArgs>(mModel_OnEntityAdded);
417      mModel.OnEntityRemoved +=
418          new EventHandler<EntityEventArgs>(mModel_OnEntityRemoved);
419      mModel.OnAmbienceChanged +=
420          new EventHandler<AmbienceEventArgs>(mModel_OnAmbienceChanged);
421    }
422
423    // ------------------------------------------------------------------
424    /// <summary>
425    /// Passes the OnAmbienceChanged event on.
426    /// </summary>
427    /// <param name="sender">object</param>
428    /// <param name="e">AmbienceEventArgs</param>
429    // ------------------------------------------------------------------
430    void mModel_OnAmbienceChanged(
431        object sender,
432        AmbienceEventArgs e) {
433      RaiseOnAmbienceChanged(e);
434    }
435
436    // ------------------------------------------------------------------
437    /// <summary>
438    /// Passes the OnEntityRemoved event on.
439    /// </summary>
440    /// <param name="sender">object</param>
441    /// <param name="e">EntityEventArgs</param>
442    // ------------------------------------------------------------------
443    void mModel_OnEntityRemoved(
444        object sender,
445        EntityEventArgs e) {
446      RaiseOnEntityRemoved(e);
447    }
448
449    // ------------------------------------------------------------------
450    /// <summary>
451    /// Passes the OnEntityAdded event on.
452    /// </summary>
453    /// <param name="sender">object</param>
454    /// <param name="e">EntityEventArgs</param>
455    // ------------------------------------------------------------------
456    void mModel_OnEntityAdded(
457        object sender,
458        EntityEventArgs e) {
459      RaiseOnEntityAdded(e);
460    }
461
462    // ------------------------------------------------------------------
463    /// <summary>
464    /// Bubbles the OnHistoryChange event.
465    /// </summary>
466    /// <param name="sender">The source of the event.</param>
467    /// <param name="e">The <see cref="T:System.EventArgs"/> instance
468    /// containing the event data.</param>
469    // ------------------------------------------------------------------
470    void mUndoManager_OnHistoryChange(object sender, EventArgs e) {
471      RaiseOnHistoryChange();
472    }
473
474    #region Methods
475
476    // ------------------------------------------------------------------
477    /// <summary>
478    /// Activates the text editor for the given text provider.
479    /// </summary>
480    /// <param name="textProvider">ITextProvider</param>
481    /// <returns>bool: True if sucessful, false if not.</returns>
482    // ------------------------------------------------------------------
483    public abstract bool ActivateTextEditor(ITextProvider textProvider);
484
485    // ------------------------------------------------------------------
486    /// <summary>
487    /// Changes the paint style of the selected entities.
488    /// </summary>
489    /// <param name="paintStyle">IPaintStyle</param>
490    // ------------------------------------------------------------------
491    public void ChangeStyle(IPaintStyle paintStyle) {
492
493      // Note that you need a copy of the selected item otherwise the
494      // undo/redo will fail once the selection has changed
495      FillStyleCommand cmd = new FillStyleCommand(
496          this,
497          this.Model.Selection.SelectedItems.Copy(),
498          paintStyle);
499
500      this.UndoManager.AddUndoCommand(cmd);
501      cmd.Redo();
502    }
503
504    // ------------------------------------------------------------------
505    /// <summary>
506    /// Changes the pen style  of the selected entities.
507    /// </summary>
508    /// <param name="penStyle">The pen style.</param>
509    // ------------------------------------------------------------------
510    public void ChangeStyle(IPenStyle penStyle) {
511      PenStyleCommand cmd = new PenStyleCommand(
512          this,
513          this.Model.Selection.SelectedItems.Copy(),
514          penStyle);
515
516      this.UndoManager.AddUndoCommand(cmd);
517
518      cmd.Redo();
519    }
520
521    #region Event Raisers
522
523    // ------------------------------------------------------------------
524    /// <summary>
525    /// Raises the OnShowContextMenu event
526    /// </summary>
527    /// <param name="e">EntityMenuEventArgs</param>
528    // ------------------------------------------------------------------
529    public virtual void RaiseOnShowContextMenu(EntityMenuEventArgs e) {
530      EventHandler<EntityMenuEventArgs> handler = OnShowContextMenu;
531      if (handler != null) {
532        handler(this, e);
533      }
534    }
535
536    // ------------------------------------------------------------------
537    /// <summary>
538    /// Raises the OnHistory change.
539    /// </summary>
540    // ------------------------------------------------------------------
541    public virtual void RaiseOnHistoryChange() {
542      EventHandler<HistoryChangeEventArgs> handler = OnHistoryChange;
543      if (handler != null) {
544        handler(this, new HistoryChangeEventArgs(
545            this.UndoManager.RedoText,
546            this.UndoManager.UndoText));
547      }
548    }
549
550    // ------------------------------------------------------------------
551    /// <summary>
552    /// Raises the <see cref="OnToolDeactivate"/> event.
553    /// </summary>
554    /// <param name="e">ConnectionCollection event argument</param>
555    // ------------------------------------------------------------------
556    public virtual void RaiseOnToolDeactivate(ToolEventArgs e) {
557      EventHandler<ToolEventArgs> handler = OnToolDeactivate;
558      if (handler != null) {
559        handler(this, e);
560      }
561    }
562
563    // ------------------------------------------------------------------
564    /// <summary>
565    /// Raises the <see cref="OnToolActivate"/> event
566    /// </summary>
567    /// <param name="e">ConnectionCollection event argument</param>
568    // ------------------------------------------------------------------
569    public virtual void RaiseOnToolActivate(ToolEventArgs e) {
570      EventHandler<ToolEventArgs> handler = OnToolActivate;
571      if (handler != null) {
572        handler(this, e);
573      }
574    }
575
576    // ------------------------------------------------------------------
577    /// <summary>
578    /// Raises the OnShowSelectionProperties event.
579    /// </summary>
580    /// <param name="e">The
581    /// <see cref="T:Netron.Diagramming.Core.SelectionEventArgs"/>
582    /// instance containing the event data.</param>
583    // ------------------------------------------------------------------
584    public virtual void RaiseOnShowSelectionProperties(SelectionEventArgs e) {
585      EventHandler<SelectionEventArgs> handler = OnShowSelectionProperties;
586      if (handler != null) {
587        handler(this, e);
588      }
589    }
590
591    // ------------------------------------------------------------------
592    /// <summary>
593    /// Raises the <see cref="OnMouseDown "/> event.
594    /// </summary>
595    /// <param name="e">The
596    /// <see cref="T:System.Windows.Forms.MouseEventArgs"/> instance
597    /// containing the event data.</param>
598    // ------------------------------------------------------------------
599    protected virtual void RaiseOnMouseDown(MouseEventArgs e) {
600      if (OnMouseDown != null)
601        OnMouseDown(this, e);
602    }
603
604    // ------------------------------------------------------------------
605    /// <summary>
606    /// Raises the <see cref="OnEntityAdded"/> event.
607    /// </summary>
608    /// <param name="e">The
609    /// <see cref="T:Netron.Diagramming.Core.EntityEventArgs"/> instance
610    /// containing the event data.</param>
611    // ------------------------------------------------------------------
612    protected virtual void RaiseOnEntityAdded(EntityEventArgs e) {
613      EventHandler<EntityEventArgs> handler = OnEntityAdded;
614      if (handler != null) {
615        handler(this, e);
616      }
617    }
618
619    // ------------------------------------------------------------------
620    /// <summary>
621    /// Raises the <see cref="OnEntityRemoved"/> event.
622    /// </summary>
623    /// <param name="e">The
624    /// <see cref="T:Netron.Diagramming.Core.EntityEventArgs"/> instance
625    /// containing the event data.</param>
626    // ------------------------------------------------------------------
627    protected virtual void RaiseOnEntityRemoved(EntityEventArgs e) {
628      EventHandler<EntityEventArgs> handler = OnEntityRemoved;
629      if (handler != null) {
630        handler(this, e);
631      }
632    }
633
634    // ------------------------------------------------------------------
635    /// <summary>
636    /// Raises the <see cref="OnAmbienceChanged"/> event.
637    /// </summary>
638    /// <param name="e">AmbienceEventArgs</param>
639    // ------------------------------------------------------------------
640    protected virtual void RaiseOnAmbienceChanged(AmbienceEventArgs e) {
641      EventHandler<AmbienceEventArgs> handler = OnAmbienceChanged;
642      if (handler != null) {
643        handler(this, e);
644      }
645    }
646
647    #endregion
648
649    #region Tool (de)activation methods
650
651    // ------------------------------------------------------------------
652    /// <summary>
653    /// Deactivates the given tool.
654    /// </summary>
655    /// <param name="tool">a registered ITool</param>
656    /// <returns>bool: True if successful.</returns>
657    // ------------------------------------------------------------------
658    public bool DeactivateTool(ITool tool) {
659      bool flag = false;
660      if (tool != null && tool.Enabled && tool.IsActive) {
661        //IEnumerator iEnumerator = tools.GetEnumerator();
662        //Tool tool2 = null;
663        //while (iEnumerator.MoveNext())
664        //{
665        //    tool2 = iEnumerator.Current is Tool;
666        //    if (tool2 != null && tool2 != tool)
667        //    {
668        //        tool2.ToolDeactivating(tool);
669        //    }
670        //}
671        flag = tool.DeactivateTool();
672        if (flag && eventsEnabled) {
673          RaiseOnToolDeactivate(new ToolEventArgs(tool));
674        }
675      }
676      return flag;
677    }
678
679    // ------------------------------------------------------------------
680    /// <summary>
681    /// Deactivates all tools.
682    /// </summary>
683    /// <returns>bool: True if successful.</returns>
684    // ------------------------------------------------------------------
685    public bool DeactivateAllTools() {
686      bool successful = true;
687
688      // If the deactivation of any tool returns false, then we will
689      // return false.
690      foreach (ITool tool in this.Tools) {
691        successful = successful & this.DeactivateTool(tool);
692      }
693      this.activeTool = null;
694      return successful;
695    }
696
697    // ------------------------------------------------------------------
698    /// <summary>
699    /// Activates the tool with the given name
700    /// </summary>
701    /// <param name="toolName"></param>
702    // ------------------------------------------------------------------
703    public void ActivateTool(string toolName) {
704      if (!controllerEnabled)
705        return;
706
707      //using anonymous method here
708      Predicate<ITool> predicate = delegate(ITool tool) {
709        if (tool.Name.ToLower() == toolName.ToLower())//not case sensitive
710          return true;
711        else
712          return false;
713      };
714
715      // First deactivate the current tool.
716      if (this.activeTool != null) {
717        this.activeTool.DeactivateTool();
718      }
719      ITool foundTool = this.registeredTools.Find(predicate);
720      ActivateTool(foundTool);
721    }
722
723    // ------------------------------------------------------------------
724    /// <summary>
725    /// Suspends all tools
726    /// </summary>
727    // ------------------------------------------------------------------
728    public void SuspendAllTools() {
729      foreach (ITool tool in this.Tools) {
730        tool.IsSuspended = true;
731      }
732    }
733
734    // ------------------------------------------------------------------
735    /// <summary>
736    /// Unsuspends all tools.
737    /// </summary>
738    // ------------------------------------------------------------------
739    public void UnsuspendAllTools() {
740      foreach (ITool tool in this.Tools) {
741        tool.IsSuspended = false;
742      }
743    }
744
745    // ------------------------------------------------------------------
746    /// <summary>
747    /// Activates a registered tool
748    /// </summary>
749    /// <param name="tool">a registered ITool</param>
750    /// <returns>bool: Returns if the activation was successful.  True is
751    /// returned if it was, false if not.</returns>
752    // ------------------------------------------------------------------
753    private bool ActivateTool(ITool tool) {
754      if (!controllerEnabled)
755        return false;
756      bool flag = false;
757      if (tool != null && tool.CanActivate) {
758        flag = tool.ActivateTool();
759        this.activeTool = tool;
760        if (flag && eventsEnabled) {
761          RaiseOnToolActivate(new ToolEventArgs(tool));
762        }
763      }
764      return flag;
765    }
766
767    #endregion
768
769    // ------------------------------------------------------------------
770    /// <summary>
771    /// Adds the given tool.
772    /// </summary>
773    /// <param name="tool">The tool.</param>
774    // ------------------------------------------------------------------
775    public void AddTool(ITool tool) {
776      tool.Controller = this;
777      // Add the tool to the collection even if it doesn't attach to
778      // anything (yet)
779      registeredTools.Add(tool);
780
781      IMouseListener mouseTool = null;
782      if ((mouseTool = tool as IMouseListener) != null)
783        mouseListeners.Add(mouseTool);
784
785      IKeyboardListener keyboardTool = null;
786      if ((keyboardTool = tool as IKeyboardListener) != null)
787        keyboardListeners.Add(keyboardTool);
788
789      IDragDropListener dragdropTool = null;
790      if ((dragdropTool = tool as IDragDropListener) != null)
791        dragdropListeners.Add(dragdropTool);
792
793      // Watch when the tool is (de)activated so we can pass it on.
794      tool.OnToolActivate +=
795          new EventHandler<ToolEventArgs>(AddedTool_OnToolActivate);
796
797      tool.OnToolDeactivate +=
798          new EventHandler<ToolEventArgs>(AddedTool_OnToolDeactivate);
799    }
800
801    // ------------------------------------------------------------------
802    /// <summary>
803    /// Called when an added tool is deactivated.  The event is passed on
804    /// by calling RaiseOnToolDeactivate.
805    /// </summary>
806    /// <param name="sender">object</param>
807    /// <param name="e">ToolEventArgs</param>
808    // ------------------------------------------------------------------
809    protected void AddedTool_OnToolDeactivate(object sender, ToolEventArgs e) {
810      ITool nextActiveToolInList = null;
811      if (this.activeTool == e.Properties) {
812        foreach (ITool tool in this.Tools) {
813          if (tool.IsActive) {
814            nextActiveToolInList = tool;
815            break;
816          }
817        }
818        activeTool = nextActiveToolInList;
819      }
820      this.RaiseOnToolDeactivate(e);
821    }
822
823    // ------------------------------------------------------------------
824    /// <summary>
825    /// Called when an added tool is activated.  The event is passed on
826    /// by calling RaiseOnToolActivate.
827    /// </summary>
828    /// <param name="sender">object</param>
829    /// <param name="e">ToolEventArgs</param>
830    // ------------------------------------------------------------------
831    protected void AddedTool_OnToolActivate(object sender, ToolEventArgs e) {
832      this.RaiseOnToolActivate(e);
833    }
834
835    #region Activity
836
837    // ------------------------------------------------------------------
838    /// <summary>
839    /// Adds the given activity to the controller.
840    /// </summary>
841    /// <param name="activity">The activity.</param>
842    // ------------------------------------------------------------------
843    public void AddActivity(IActivity activity) {
844
845      registeredActivity.Add(activity);
846    }
847
848    // ------------------------------------------------------------------
849    /// <summary>
850    /// Runs the given activity.
851    /// </summary>
852    /// <param name="activity">The activity.</param>
853    // ------------------------------------------------------------------
854    protected void RunActivity(IActivity activity) {
855      if (activity == null) return;
856      PrepareActivity(activity);
857
858      activity.Run();
859
860    }
861
862    // ------------------------------------------------------------------
863    /// <summary>
864    /// Runs the given activity.
865    /// </summary>
866    /// <param name="activity">The activity.</param>
867    /// <param name="milliseconds">The milliseconds.</param>
868    // ------------------------------------------------------------------
869    protected void RunActivity(IActivity activity, int milliseconds) {
870      if (activity == null) return;
871      PrepareActivity(activity);
872      activity.Run(milliseconds);
873    }
874
875    // ------------------------------------------------------------------
876    /// <summary>
877    /// Prepares the activity.
878    /// </summary>
879    /// <param name="activity">The activity.</param>
880    // ------------------------------------------------------------------
881    private void PrepareActivity(IActivity activity) {
882      if (activity is IAction)
883        (activity as IAction).Model = this.Model;
884      if (activity is ILayout) {
885        (activity as ILayout).Bounds = parentControl.ClientRectangle;
886        (activity as ILayout).Center = new PointF(parentControl.ClientRectangle.Width / 2, parentControl.ClientRectangle.Height / 2);
887      }
888    }
889
890    // ------------------------------------------------------------------
891    /// <summary>
892    /// Runs the activity with the name specified.  If no activity could
893    /// by found with the given name then an exception is thrown.
894    /// </summary>
895    /// <param name="activityName">string: The name of the
896    /// activity to run.</param>
897    // ------------------------------------------------------------------
898    public void RunActivity(string activityName) {
899      if (!controllerEnabled)
900        return;
901
902      this.View.CurrentCursor = Cursors.WaitCursor;
903      controllerEnabled = false;
904
905      IActivity foundActivity = FindActivity(activityName);
906      if (foundActivity != null) {
907        RunActivity(foundActivity);
908      }
909
910      controllerEnabled = true;
911      this.View.CurrentCursor = Cursors.Default;
912
913      // After returning the canvas back to "normal", if the activity
914      // wasn't found throw an exception (as specified by IController).
915      if (foundActivity == null) {
916        throw new Exception("Activity '" + activityName +
917            "' could not be found.");
918      }
919    }
920
921    // ------------------------------------------------------------------
922    /// <summary>
923    /// Finds the activity with the given name.
924    /// </summary>
925    /// <param name="name">The name.</param>
926    /// <returns>IActivity</returns>
927    // ------------------------------------------------------------------
928    protected IActivity FindActivity(string name) {
929      //using anonymous method here
930      Predicate<IActivity> predicate = delegate(IActivity activity) {
931        if (activity.Name.ToLower() == name.ToLower())//not case sensitive
932          return true;
933        else
934          return false;
935      };
936      return this.registeredActivity.Find(predicate);
937
938    }
939
940    // ------------------------------------------------------------------
941    /// <summary>
942    /// Runs the given activity for the specified time span.
943    /// </summary>
944    /// <param name="name">The name.</param>
945    /// <param name="milliseconds">The milliseconds.</param>
946    // ------------------------------------------------------------------
947    public void RunActivity(string name, int milliseconds) {
948      if (!controllerEnabled)
949        return;
950
951      IActivity foundActivity = FindActivity(name);
952      if (foundActivity != null)
953        RunActivity(foundActivity, milliseconds);
954    }
955
956    #endregion
957
958    // ------------------------------------------------------------------
959    /// <summary>
960    /// Attaches this controller to the surface.
961    /// </summary>
962    /// <param name="surface">The surface.</param>
963    // ------------------------------------------------------------------
964    protected virtual void AttachToSurface(IDiagramControl surface) {
965      #region Mouse events
966      surface.MouseDown += new MouseEventHandler(OnSurfaceMouseDown);
967      surface.MouseUp += new MouseEventHandler(OnSurfaceMouseUp);
968      surface.MouseMove += new MouseEventHandler(OnSurfaceMouseMove);
969      surface.MouseHover += new EventHandler(OnSurfaceMouseHover);
970      surface.MouseWheel += new MouseEventHandler(surface_MouseWheel);
971      #endregion
972
973      #region Keyboard events
974      surface.KeyDown += new KeyEventHandler(surface_KeyDown);
975      surface.KeyUp += new KeyEventHandler(surface_KeyUp);
976      surface.KeyPress += new KeyPressEventHandler(surface_KeyPress);
977      #endregion
978
979      #region Dragdrop events
980      surface.DragDrop += new DragEventHandler(surface_DragDrop);
981      surface.DragEnter += new DragEventHandler(surface_DragEnter);
982      surface.DragLeave += new EventHandler(surface_DragLeave);
983      surface.DragOver += new DragEventHandler(surface_DragOver);
984      surface.GiveFeedback +=
985          new GiveFeedbackEventHandler(surface_GiveFeedback);
986      #endregion
987    }
988
989    // ------------------------------------------------------------------
990    /// <summary>
991    /// Handles the MouseWheel event of the surface control.
992    /// <remarks>In the WinForm implementation this routine is not called
993    /// because it gives some flickering effects; the hotkeys are
994    /// implemented in the overriden OnMouseWheel method instead.</remarks>
995    /// </summary>
996    /// <param name="sender">The source of the event.</param>
997    /// <param name="e">The
998    /// <see cref="T:System.Windows.Forms.MouseEventArgs"/> instance
999    /// containing the event data.</param>
1000    // ------------------------------------------------------------------
1001    void surface_MouseWheel(object sender, MouseEventArgs e) {
1002      Point p = View.Origin;
1003      SizeF magnification = View.Magnification;
1004      int newValue = 0;
1005
1006      if ((Control.ModifierKeys & Keys.Control) == Keys.Control) {
1007        #region Zooming
1008
1009        SizeF s = magnification;
1010
1011        // If zooming in, e.Delta is < 0 so a value of 1.1 is used to
1012        // offset the current magnification by.  One mouse wheel
1013        // position on my PC corresponds to a delta of 120 (positive
1014        // for zooming out, neg for zooming in).
1015        float alpha = e.Delta > 0 ? 1.1F : 0.9F;
1016        View.Magnification = new SizeF(
1017            s.Width * alpha,
1018            s.Height * alpha);
1019
1020        float w = (float)parentControl.AutoScrollPosition.X /
1021            (float)parentControl.AutoScrollMinSize.Width;
1022
1023        float h = (float)parentControl.AutoScrollPosition.Y /
1024            (float)parentControl.AutoScrollMinSize.Height;
1025
1026        // Resize the scrollbars proportionally to keep the actual
1027        // canvas constant.
1028        //s = new SizeF(
1029        //    parentControl.AutoScrollMinSize.Width * alpha,
1030        //    parentControl.AutoScrollMinSize.Height * alpha);
1031
1032        //parentControl.AutoScrollMinSize = Size.Round(s);
1033        RectangleF pageBounds = Model.CurrentPage.Bounds;
1034        pageBounds.Inflate(s);
1035        SizeF deltaSize = new SizeF(
1036            pageBounds.Width - parentControl.ClientRectangle.Width,
1037            pageBounds.Height - parentControl.ClientRectangle.Height);
1038
1039        if ((deltaSize.Width > 0) && (deltaSize.Height > 0)) {
1040          parentControl.AutoScrollMinSize = Size.Round(deltaSize);
1041        }
1042
1043        //Point v = Origin;
1044        //v.Offset(
1045        //    Convert.ToInt32((alpha - 1) * v.X),
1046        //    Convert.ToInt32((alpha - 1) * v.Y));
1047        //v.X = (int)Math.Round((double)(v.X - alpha));
1048        //v.Y = (int)Math.Round((double)(v.Y - alpha));
1049        //Origin = v;
1050
1051        #endregion
1052      } else if ((Control.ModifierKeys & Keys.Shift) == Keys.Shift) {
1053        #region Pan horizontal
1054        newValue = p.X - Math.Sign(e.Delta) * 20;
1055        if (newValue > 0)
1056          View.Origin = new Point(newValue, p.Y);
1057        else
1058          View.Origin = new Point(0, p.Y);
1059
1060        #endregion
1061      } else {
1062        #region Default vertical scroll
1063        newValue = View.Origin.Y -
1064            Math.Sign(e.Delta) * 20;
1065
1066        if (newValue > 0)
1067          View.Origin = new Point(
1068              View.Origin.X,
1069              newValue);
1070        else
1071          View.Origin = new Point(
1072              View.Origin.X,
1073              0);
1074        #endregion
1075      }
1076
1077      this.parentControl.AutoScrollPosition = View.Origin;
1078      HandledMouseEventArgs eventargs = e as HandledMouseEventArgs;
1079      if (eventargs != null)
1080        eventargs.Handled = true;
1081      View.Invalidate();
1082    }
1083
1084    #region DragDrop event handlers
1085
1086    /// <summary>
1087    /// Handles the GiveFeedback event of the surface control.
1088    /// </summary>
1089    /// <param name="sender">The source of the event.</param>
1090    /// <param name="e">The <see cref="T:System.Windows.Forms.GiveFeedbackEventArgs"/> instance containing the event data.</param>
1091    void surface_GiveFeedback(object sender, GiveFeedbackEventArgs e) {
1092      if (!controllerEnabled) {
1093        return;
1094      }
1095
1096      foreach (IDragDropListener listener in dragdropListeners) {
1097        listener.GiveFeedback(e);
1098      }
1099    }
1100    /// <summary>
1101    /// Handles the DragOver event of the surface control.
1102    /// </summary>
1103    /// <param name="sender">The source of the event.</param>
1104    /// <param name="e">The <see cref="T:System.Windows.Forms.DragEventArgs"/> instance containing the event data.</param>
1105    void surface_DragOver(object sender, DragEventArgs e) {
1106      if (!controllerEnabled) {
1107        return;
1108      }
1109
1110      foreach (IDragDropListener listener in dragdropListeners) {
1111        listener.OnDragOver(e);
1112      }
1113    }
1114
1115    /// <summary>
1116    /// Handles the DragLeave event of the surface control.
1117    /// </summary>
1118    /// <param name="sender">The source of the event.</param>
1119    /// <param name="e">The <see cref="T:System.EventArgs"/> instance containing the event data.</param>
1120    void surface_DragLeave(object sender, EventArgs e) {
1121      if (!controllerEnabled) {
1122        return;
1123      }
1124
1125      foreach (IDragDropListener listener in dragdropListeners) {
1126        listener.OnDragLeave(e);
1127      }
1128    }
1129
1130    /// <summary>
1131    /// Handles the DragEnter event of the surface control.
1132    /// </summary>
1133    /// <param name="sender">The source of the event.</param>
1134    /// <param name="e">The <see cref="T:System.Windows.Forms.DragEventArgs"/> instance containing the event data.</param>
1135    void surface_DragEnter(object sender, DragEventArgs e) {
1136      if (!controllerEnabled) {
1137        return;
1138      }
1139
1140      foreach (IDragDropListener listener in dragdropListeners) {
1141        listener.OnDragEnter(e);
1142      }
1143    }
1144
1145    /// <summary>
1146    /// Handles the DragDrop event of the surface control.
1147    /// </summary>
1148    /// <param name="sender">The source of the event.</param>
1149    /// <param name="e">The <see cref="T:System.Windows.Forms.DragEventArgs"/> instance containing the event data.</param>
1150    void surface_DragDrop(object sender, DragEventArgs e) {
1151      if (!controllerEnabled) {
1152        return;
1153      }
1154
1155      foreach (IDragDropListener listener in dragdropListeners) {
1156        listener.OnDragDrop(e);
1157      }
1158    }
1159    #endregion
1160
1161    #region Keyboard event handlers
1162    void surface_KeyPress(object sender, KeyPressEventArgs e) {
1163
1164      foreach (IKeyboardListener listener in keyboardListeners) {
1165        listener.KeyPress(e);
1166      }
1167
1168      foreach (IDiagramEntity entity in this.Model.Selection.SelectedItems) {
1169        if (entity is IKeyboardListener) {
1170          (entity as IKeyboardListener).KeyPress(e);
1171        }
1172      }
1173    }
1174
1175    void surface_KeyUp(object sender, KeyEventArgs e) {
1176
1177      foreach (IKeyboardListener listener in keyboardListeners) {
1178        listener.KeyUp(e);
1179      }
1180
1181      foreach (IDiagramEntity entity in this.Model.Selection.SelectedItems) {
1182        if (entity is IKeyboardListener) {
1183          (entity as IKeyboardListener).KeyUp(e);
1184        }
1185      }
1186    }
1187
1188    void surface_KeyDown(object sender, KeyEventArgs e) {
1189      foreach (IKeyboardListener listener in keyboardListeners) {
1190        listener.KeyDown(e);
1191      }
1192
1193      foreach (IDiagramEntity entity in this.Model.Selection.SelectedItems) {
1194        if (entity is IKeyboardListener) {
1195          (entity as IKeyboardListener).KeyDown(e);
1196        }
1197      }
1198    }
1199
1200    #endregion
1201
1202    #region Mouse event handlers
1203    /// <summary>
1204    /// Implements the observer pattern for the mouse hover event,
1205    /// communicating the event to all listeners implementing the
1206    /// necessary interface.
1207    /// </summary>
1208    /// <param name="sender">The source of the event.</param>
1209    /// <param name="e">The <see cref="T:System.EventArgs"/> instance
1210    /// containing the event data.</param>
1211    protected virtual void OnSurfaceMouseHover(object sender, EventArgs e) {
1212      //if (eventsEnabled)
1213      //    RaiseOnMouseHover(e);
1214      //if (!controllerEnabled)
1215      //    return; 
1216    }
1217    /// <summary>
1218    /// Implements the observer pattern for the mouse down event,
1219    /// communicating the event to all listeners implementing the
1220    /// necessary interface.
1221    /// </summary>
1222    /// <param name="sender">The source of the event.</param>
1223    /// <param name="e">The
1224    /// <see cref="T:System.Windows.Forms.MouseEventArgs"/> instance
1225    /// containing the event data.</param>
1226    protected virtual void OnSurfaceMouseDown(
1227        object sender,
1228        MouseEventArgs e) {
1229      #region Coordinates logic
1230      // Get a point adjusted by the current scroll position and zoom factor           
1231      Point p = Point.Round(
1232          this.View.ViewToWorld(this.View.DeviceToView(e.Location)));
1233
1234      HandledMouseEventArgs ce =
1235          new HandledMouseEventArgs(
1236          e.Button,
1237          e.Clicks,
1238          p.X,
1239          p.Y,
1240          e.Delta);
1241      #endregion
1242
1243      if (eventsEnabled)
1244        RaiseOnMouseDown(ce);
1245      if (!controllerEnabled || ce.Handled)
1246        return;
1247      this.parentControl.Focus();
1248
1249      //(parentControl as Win.DiagramControl).toolTip.Show("Yihaaa", parentControl as Win.DiagramControl, ce.Location);
1250
1251      //this selection process will work independently of the tools because
1252      //some tools need the current selection or hit entity
1253      //On the other hand, when drawing a simple rectangle for example the selection
1254      //should be off, so there is an overhead.
1255      //Selection.CollectEntitiesAt(e.Location);
1256
1257      //raise the event to give the host the opportunity to show the properties of the selected item(s)
1258      //Note that if the selection is empty the property grid will show 'nothing'.
1259      RaiseOnShowSelectionProperties(new SelectionEventArgs(this.Model.Selection.SelectedItems.ToArray()));
1260
1261      foreach (IMouseListener listener in mouseListeners) {
1262        if (listener.MouseDown(ce))
1263          break;
1264      }
1265    }
1266    /// <summary>
1267    /// Handles the MouseMove event of the surface control.
1268    /// </summary>
1269    /// <param name="sender">The source of the event.</param>
1270    /// <param name="e">The
1271    /// <see cref="T:System.Windows.Forms.MouseEventArgs"/> instance
1272    /// containing the event data.</param>
1273    protected virtual void OnSurfaceMouseMove(object sender, MouseEventArgs e) {
1274      if (!controllerEnabled)
1275        return;
1276
1277      #region Coordinates logic
1278      // Get a point adjusted by the current scroll position and zoom
1279      // factor.
1280      //Point p = new Point(e.X - parentControl.AutoScrollPosition.X, e.Y - parentControl.AutoScrollPosition.Y);
1281      Point p = Point.Round(this.View.ViewToWorld(
1282          this.View.DeviceToView(e.Location)));
1283
1284      MouseEventArgs ce = new MouseEventArgs(
1285          e.Button,
1286          e.Clicks,
1287          p.X,
1288          p.Y,
1289          e.Delta);
1290
1291      #endregion
1292      foreach (IMouseListener listener in mouseListeners) {
1293        listener.MouseMove(ce);
1294      }
1295    }
1296
1297    /// <summary>
1298    /// Handles the MouseUp event of the surface control.
1299    /// </summary>
1300    /// <param name="sender">The source of the event.</param>
1301    /// <param name="e">The <see cref="T:System.Windows.Forms.MouseEventArgs"/> instance containing the event data.</param>
1302    protected virtual void OnSurfaceMouseUp(object sender, System.Windows.Forms.MouseEventArgs e) {
1303      if (!controllerEnabled)
1304        return;
1305      #region Coordinates logic
1306      // Get a point adjusted by the current scroll position and zoom factor
1307      //Point p = new Point(e.X - parentControl.AutoScrollPosition.X, e.Y - parentControl.AutoScrollPosition.Y);
1308      Point p = Point.Round(this.View.ViewToWorld(this.View.DeviceToView(e.Location)));
1309      MouseEventArgs ce = new MouseEventArgs(e.Button, e.Clicks, p.X, p.Y, e.Delta);
1310      #endregion
1311      foreach (IMouseListener listener in mouseListeners) {
1312        listener.MouseUp(ce);
1313      }
1314    }
1315
1316
1317    #endregion
1318
1319    // ------------------------------------------------------------------
1320    /// <summary>
1321    /// Undo of the last action
1322    /// </summary>
1323    /// <remarks>Calling this on a class level will call the Undo method
1324    /// of the last ICommand in the stack.</remarks>
1325    // ------------------------------------------------------------------
1326    public void Undo() {
1327      // Reset the tracker or show the tracker after the undo operation
1328      // since the undo does not take care of it
1329      this.View.ResetTracker();
1330      mUndoManager.Undo();
1331      this.View.ShowTracker();
1332      this.View.Invalidate();
1333    }
1334
1335    // ------------------------------------------------------------------
1336    /// <summary>
1337    /// Performs the actual action or redo in case the actions was undone
1338    /// before.
1339    /// </summary>
1340    /// <remarks>Calling this on a class level will call the Redo method
1341    /// of the last ICommand in the stack.</remarks>
1342    // ------------------------------------------------------------------
1343    public void Redo() {
1344      mUndoManager.Redo();
1345      this.View.ShowTracker();
1346    }
1347
1348    // ------------------------------------------------------------------
1349    /// <summary>
1350    /// Selects all entities on the current page.  The selection is
1351    /// cleared first.
1352    /// </summary>
1353    // ------------------------------------------------------------------
1354    public void SelectAll() {
1355      this.View.ResetTracker();
1356      this.Model.Selection.Clear();
1357      this.Model.Selection.SelectedItems = this.Model.CurrentPage.Entities;
1358      this.View.ShowTracker();
1359      this.View.Invalidate();
1360    }
1361
1362    // ------------------------------------------------------------------
1363    /// <summary>
1364    /// Navigates to the next page.  Nothing is performed if the last page
1365    /// is currently selected and 'wrap' is false.  If 'wrap' is true,
1366    /// then the first page is selected.
1367    /// </summary>
1368    /// <param name="wrap">bool: Specifies if the collection is wrapped
1369    /// when the end is reached.</param>
1370    // ------------------------------------------------------------------
1371    public void GoForward(bool wrap) {
1372      // We can't go anywhere if there's only one page!
1373      if (Model.Pages.Count == 1) {
1374        return;
1375      }
1376
1377      int index = Model.Pages.IndexOf(Model.CurrentPage);
1378
1379      int newIndex = 0;  // The index of the page to select.
1380
1381      if (index >= (Model.Pages.Count - 1)) {
1382        // The last page is currently active, so if 'wrap' is
1383        // false then just return.
1384        if (wrap == false) {
1385          return;
1386        }
1387
1388        // Otherwise, if 'wrap' is true then we want the first page
1389        // in the collection to be active.
1390        newIndex = 0;
1391      } else {
1392        newIndex = index + 1;
1393      }
1394
1395      DeactivateAllTools();
1396      View.HideTracker();  // Just in case there are selected items.
1397      Model.SetCurrentPage(Model.Pages[newIndex]);
1398      View.Invalidate();
1399    }
1400
1401    // ------------------------------------------------------------------
1402    /// <summary>
1403    /// Navigates to the previous page.  Nothing is performed if the first
1404    /// page is currently selected and 'wrap' is false.  If 'wrap' is
1405    /// true, then the last page is selected if the current page is the
1406    /// first page.
1407    /// </summary>
1408    /// <param name="wrap">bool: Specifies if the collection is wrapped
1409    /// when the start is reached.</param>
1410    // ------------------------------------------------------------------
1411    public void GoBack(bool wrap) {
1412      // We can't go anywhere if there's only one page!
1413      if (Model.Pages.Count == 1) {
1414        return;
1415      }
1416
1417      int index = Model.Pages.IndexOf(Model.CurrentPage);
1418
1419      int newIndex = 0;  // The index of the page to select.
1420
1421      if (index == 0) {
1422        // The first page is currently active, so if 'wrap' is
1423        // false then just return.
1424        if (wrap == false) {
1425          return;
1426        }
1427
1428        // Otherwise, since 'wrap' is true then we want the last page
1429        // in the collection to be active.
1430        newIndex = Model.Pages.Count - 1;
1431      } else {
1432        newIndex = index - 1;
1433      }
1434
1435      DeactivateAllTools();
1436      View.HideTracker();  // Just in case there are selected items.
1437      Model.SetCurrentPage(Model.Pages[newIndex]);
1438      View.Invalidate();
1439    }
1440    #endregion
1441
1442  }
1443}
Note: See TracBrowser for help on using the repository browser.