1 namespace System.Workflow.ComponentModel.Design
2 {
3     using System;
4     using System.IO;
5     using System.Data;
6     using System.Drawing;
7     using System.Security;
8     using System.Resources;
9     using System.Reflection;
10     using System.Diagnostics;
11     using System.Collections;
12     using System.Windows.Forms;
13     using System.ComponentModel;
14     using System.Drawing.Design;
15     using System.Drawing.Imaging;
16     using System.Drawing.Printing;
17     using System.Drawing.Drawing2D;
18     using System.Workflow.Interop;
19     using System.Collections.Generic;
20     using System.Windows.Forms.Design;
21     using System.Security.Permissions;
22     using System.ComponentModel.Design;
23     using System.Runtime.InteropServices;
24     using System.Collections.ObjectModel;
25     using System.Diagnostics.CodeAnalysis;
26     /// What did I change in this file
27     /// 1. Eliminated the layout manager and introduced classes for WorkflowLayout and PrintPreviewLayout
28     /// 2. Eliminated the event syncing of PageSetupData change. We call performlayout on the current designer service whenever the pagesetupdata changes
29 
30     /// Designer Features:
31     /// Selection on click and thru drag rectangle
32     /// Reconfigurable background
33     /// Scrolling
34     /// Ensure Visible functionality
35     /// Accessibility
36     /// Zoom
37     /// Rehostable
38     /// Extensible
39     /// Small memory footprint
40     /// Ability to move around objects using drag drop
41     /// Ability to drop the objects using drag drop
42     /// Printing support
43     /// Theme support
44     /// Magnifier
45     /// AutoScroll
46     /// AutoExpand
47     /// USE THIS FOR PERFORMANCE TEST: Debug.WriteLine("******Root drawing: " + Convert.ToString((DateTime.Now.Ticks - ticks) / 10000) + "ms");
48     ///
49     /// Here are some details about the coordinate system,
50     ///
51     /// Screen CoOrdinate System: Starts at 0,0 of the screen
52     /// Client CoOrdinate System: Starts at 0,0 of the control
53     /// Logical CoOrdinate System: The workflowview supports zooming and scroll, we want to hide this
54     /// complexity from the activity writter and hence whenever we get a coordinate we translate it based
55     /// scroll position, zoom level and layout. This helps us to sheild the activity designers from complexity
56     /// of zooming, scaling and layouting. The designer writters deal with one coordinate system which is unscaled and
57     /// starts at 0,0
58     ///
59     ///
60 
61     [ToolboxItem(false)]
62     [ActivityDesignerTheme(typeof(AmbientTheme), Xml = WorkflowView.ThemeXml)]
63     [Obsolete("The System.Workflow.* types are deprecated.  Instead, please use the new types from System.Activities.*")]
64     public class WorkflowView : UserControl, IServiceProvider, IMessageFilter
65     {
66         #region Theme Initializer XML
67         internal const string ThemeXml =
68                 "<AmbientTheme xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/workflow\"" +
69                      " ApplyTo=\"System.Workflow.ComponentModel.Design.WorkflowView\"" +
70                      " ShowConfigErrors=\"True\"" +
71                      " DrawShadow=\"False\"" +
72                      " DrawGrayscale=\"False\"" +
73                      " DropIndicatorColor=\"0xFF006400\"" +
74                      " SelectionForeColor=\"0xFF0000FF\"" +
75                      " SelectionPatternColor=\"0xFF606060\"" +
76                      " ForeColor=\"0xFF808080\"" +
77                      " BackColor=\"0xFFFFFFFF\"" +
78                      " ShowGrid=\"False\"" +
79                      " GridColor=\"0xFFC0C0C0\"" +
80                      " TextQuality=\"Aliased\"" +
81                      " DrawRounded=\"True\"" +
82                      " ShowDesignerBorder=\"True\"" +
83                  " />";
84         #endregion
85 
86         #region Members Variables
87         [Obsolete("The System.Workflow.* types are deprecated.  Instead, please use the new types from System.Activities.*")]
88         private enum TabButtonIds { MultiPage = 1, Zoom, Pan }
89 
90         //Designer Hookup
91         private IServiceProvider serviceProvider = null;
92 
93         private ActivityDesigner rootDesigner = null;
94 
95         //Zoom
96         private float zoomLevel = 1.0f;
97         private int shadowDepth = WorkflowTheme.CurrentTheme.AmbientTheme.ShadowDepth;
98 
99         //MessageFilters
100         private List<WorkflowDesignerMessageFilter> stockMessageFilters = new List<WorkflowDesignerMessageFilter>();
101         private List<WorkflowDesignerMessageFilter> customMessageFilters = new List<WorkflowDesignerMessageFilter>();
102 
103         //
104 
105         private Bitmap viewPortBitmap = null;
106 
107         //Misc.
108         private WorkflowToolTip workflowToolTip = null;
109 
110         private CommandSet commandSet = null;
111         private DynamicAction fitAllAction = null;
112 
113         //print
114         private int prePreviewZoom = 100;
115         private Point prePreviewScroll = Point.Empty;
116         private WorkflowPrintDocument printDocument = null;
117 
118         //Active layout
119         private WorkflowLayout activeLayout = null;
120         private WorkflowLayout defaultLayout = null;
121 
122         //One time callable delegates
123         private EventHandler layoutEventHandler = null;
124         private EventHandler ensureVisibleEventHandler = null;
125 
126         private Stack<HitTestInfo> messageHitTestContexts = new Stack<HitTestInfo>();
127 
128         private HScrollBar hScrollBar;
129         private VScrollBar vScrollBar;
130 
131         private TabControl toolContainer;
132         private EventHandler idleEventListeners;
133         private EventHandler idleEventHandler;
134 
135         private bool dragDropInProgress;
136         #endregion
137 
138         #region Events
139         public event EventHandler ZoomChanged;
140         public event EventHandler RootDesignerChanged;
141         #endregion
142 
143         #region Constructor and Dispose
WorkflowView()144         public WorkflowView()
145             : this(new DesignSurface())
146         {
147         }
148 
WorkflowView(IServiceProvider serviceProvider)149         public WorkflowView(IServiceProvider serviceProvider)
150         {
151             Debug.Assert(serviceProvider != null);
152             if (serviceProvider == null)
153                 throw new ArgumentNullException("serviceProvider");
154 
155             SuspendLayout();
156             AllowDrop = true;
157             AutoScroll = false;
158             HScroll = false;
159             VScroll = false;
160             SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.UserPaint | ControlStyles.Opaque | ControlStyles.AllPaintingInWmPaint | ControlStyles.Selectable | ControlStyles.EnableNotifyMessage, true);
161 
162             this.serviceProvider = serviceProvider;
163 
164             //*****Promote the services which are accessed from other components
165             IServiceContainer serviceContainer = GetService(typeof(IServiceContainer)) as IServiceContainer;
166             if (serviceContainer != null)
167             {
168                 //Remove any existing designer service if there is any
169                 serviceContainer.RemoveService(typeof(WorkflowView));
170                 serviceContainer.AddService(typeof(WorkflowView), this);
171             }
172 
173             //set the UI Service to be used by themes
174             IUIService uiService = this.serviceProvider.GetService(typeof(IUIService)) as IUIService;
175             if (uiService != null)
176                 WorkflowTheme.UIService = uiService;
177 
178             //Make sure that we add scrollbars
179             EnsureScrollBars(new HScrollBar(), new VScrollBar());
180 
181             //Initialize the tooltip shown
182             this.workflowToolTip = new WorkflowToolTip(this);
183 
184             //Sync the global theme change event, which is fired by the theme infrastructure for theme change
185             WorkflowTheme.ThemeChanged += new EventHandler(OnThemeChange);
186 
187             //Create the core message filters
188             PopulateMessageFilters(true);
189 
190             //Set the root designer, note that the dynamic action is dependent on the DynamicActionMessageFilter pushed
191             //when the root is set.
192             RootDesigner = ActivityDesigner.GetSafeRootDesigner(this);
193             this.fitAllAction = CreateDynamicAction();
194 
195             //If the active layout is still null then we will set the default layout as active layout
196             if (this.activeLayout == null || this.defaultLayout == null)
197                 ActiveLayout = DefaultLayout = new WorkflowRootLayout(this.serviceProvider);
198 
199             //Create the local command set and update all the commands once
200             IMenuCommandService menuCommandService = GetService(typeof(IMenuCommandService)) as IMenuCommandService;
201             if (menuCommandService != null)
202             {
203                 this.commandSet = new CommandSet(this);
204                 this.commandSet.UpdatePanCommands(true);
205             }
206 
207             //Subscribe to selection change
208             ISelectionService selectionService = GetService(typeof(ISelectionService)) as ISelectionService;
209             if (selectionService != null)
210                 selectionService.SelectionChanged += new EventHandler(OnSelectionChanged);
211 
212             //In case of non VS case we need to pumpin the Keyboard messages, the user control sets
213             //focus to the child controls by default which is a problem so we need to trap the
214             //messages by adding application level message filter, in case of VS this is not required and
215             //the message filter is never called.
216             Application.AddMessageFilter(this);
217 
218             //We make sure that during the construction we dont do perform layouts on idle event
219             ResumeLayout(true);
220         }
221 
Dispose(bool disposing)222         protected override void Dispose(bool disposing)
223         {
224             //Remove the proffered services
225             if (disposing)
226             {
227                 try
228                 {
229                     SuspendLayout();
230 
231                     Application.RemoveMessageFilter(this);
232 
233                     if (this.layoutEventHandler != null)
234                     {
235                         Idle -= this.layoutEventHandler;
236                         this.layoutEventHandler = null;
237                     }
238 
239                     if (this.ensureVisibleEventHandler != null)
240                     {
241                         Idle -= this.ensureVisibleEventHandler;
242                         this.ensureVisibleEventHandler = null;
243                     }
244 
245                     if (this.idleEventHandler != null)
246                     {
247                         this.idleEventListeners = null;
248 
249                         Form host = TopLevelControl as Form;
250                         if (!Application.MessageLoop || (host != null && host.Modal))
251                             WorkflowTimer.Default.Unsubscribe(this.idleEventHandler);
252                         else
253                             Application.Idle -= this.idleEventHandler;
254                         this.idleEventHandler = null;
255                     }
256 
257                     ISelectionService selectionService = GetService(typeof(ISelectionService)) as ISelectionService;
258                     if (selectionService != null)
259                         selectionService.SelectionChanged -= new EventHandler(OnSelectionChanged);
260 
261                     //Unsubscribe the theme change
262                     WorkflowTheme.ThemeChanged -= new EventHandler(OnThemeChange);
263 
264                     //Remove the dynamic action
265                     if (this.fitAllAction != null)
266                     {
267                         this.fitAllAction.Dispose();
268                         this.fitAllAction = null;
269                     }
270 
271                     if (this.workflowToolTip != null)
272                     {
273                         ((IDisposable)this.workflowToolTip).Dispose();
274                         this.workflowToolTip = null;
275                     }
276 
277                     DisposeMessageFilters(false);
278                     DisposeMessageFilters(true);
279 
280                     //Dispose the layouts
281                     this.activeLayout = null;
282                     if (this.defaultLayout != null)
283                     {
284                         this.defaultLayout.Dispose();
285                         this.defaultLayout = null;
286                     }
287 
288                     //Destroy other resources
289                     if (this.viewPortBitmap != null)
290                     {
291                         this.viewPortBitmap.Dispose();
292                         this.viewPortBitmap = null;
293                     }
294 
295                     if (this.commandSet != null)
296                     {
297                         this.commandSet.Dispose();
298                         this.commandSet = null;
299                     }
300 
301                     HScrollBar.ValueChanged -= new EventHandler(OnScroll);
302                     VScrollBar.ValueChanged -= new EventHandler(OnScroll);
303 
304                     if (this.toolContainer != null)
305                     {
306                         Controls.Remove(this.toolContainer);
307                         this.toolContainer.TabStrip.Tabs.Clear();
308                         this.toolContainer.Dispose();
309                         this.toolContainer = null;
310                     }
311 
312                     IServiceContainer serviceContainer = GetService(typeof(IServiceContainer)) as IServiceContainer;
313                     if (serviceContainer != null)
314                     {
315                         serviceContainer.RemoveService(typeof(WorkflowView));
316                     }
317                 }
318                 finally
319                 {
320                     ResumeLayout(false);
321                 }
322             }
323 
324             base.Dispose(disposing);
325         }
326         #endregion
327 
328         #region Public Properties
329         public int Zoom
330         {
331             get
332             {
333                 return Convert.ToInt32(this.zoomLevel * 100);
334             }
335 
336             set
337             {
338                 if (Zoom == value)
339                     return;
340 
341                 if (value < AmbientTheme.MinZoom || value > AmbientTheme.MaxZoom)
342                     throw new NotSupportedException(DR.GetString(DR.ZoomLevelException2, AmbientTheme.MinZoom, AmbientTheme.MaxZoom));
343 
344                 ScrollBar hScrollBar = HScrollBar;
345                 ScrollBar vScrollBar = VScrollBar;
346 
347                 if (hScrollBar != null && vScrollBar != null)
348                 {
349                     PointF oldRelativeCenter = Point.Empty;
350                     Point oldCenter = new Point(ScrollPosition.X, ScrollPosition.Y);
351                     oldRelativeCenter = new PointF((float)oldCenter.X / (float)hScrollBar.Maximum, (float)oldCenter.Y / (float)vScrollBar.Maximum);
352 
353                     //recalculate the zoom and scroll range
354                     this.zoomLevel = (float)value / 100.0f;
355                     UpdateScrollRange();
356 
357                     //center the view again
358                     Point newCenter = new Point((int)((float)hScrollBar.Maximum * oldRelativeCenter.X), (int)((float)vScrollBar.Maximum * oldRelativeCenter.Y));
359                     ScrollPosition = new Point(newCenter.X, newCenter.Y);
360 
361                     if (this.rootDesigner != null)
362                         this.rootDesigner.Location = this.activeLayout.RootDesignerAlignment;
363 
364                     InvalidateClientRectangle(Rectangle.Empty);
365 
366                     //
367 
368                     this.activeLayout.Update(null, WorkflowLayout.LayoutUpdateReason.ZoomChanged);
369 
370                     //force command refresh
371                     //this is to workarond VS not refreshing Zoom drop down when doing area zoom-in
372                     IUIService uis = GetService(typeof(IUIService)) as IUIService;
373                     if (uis != null)
374                         uis.SetUIDirty();
375 
376                     //We need to update the zoom commands when the zoom is updated
377                     if (this.commandSet != null)
378                         this.commandSet.UpdateZoomCommands(true);
379 
380                     OnZoomChanged();
381                 }
382             }
383         }
384 
385         public ActivityDesigner RootDesigner
386         {
387             get
388             {
389                 return this.rootDesigner;
390             }
391 
392             set
393             {
394                 if (this.rootDesigner == value)
395                     return;
396 
397                 DisposeMessageFilters(false);
398 
399                 this.rootDesigner = value;
400 
401                 if (this.rootDesigner != null)
402                 {
403                     PopulateMessageFilters(false);
404                     ActiveLayout = DefaultLayout = this.rootDesigner.SupportedLayout;
405                 }
406 
407                 OnRootDesignerChanged();
408 
409                 base.PerformLayout();
410             }
411         }
412 
413         public int ShadowDepth
414         {
415             get
416             {
417                 return this.shadowDepth;
418             }
419 
420             set
421             {
422                 if (value < AmbientTheme.MinShadowDepth || value > AmbientTheme.MaxShadowDepth)
423                     throw new NotSupportedException(DR.GetString(DR.ShadowDepthException, AmbientTheme.MinShadowDepth, AmbientTheme.MaxShadowDepth));
424 
425                 if (this.shadowDepth == value)
426                     return;
427 
428                 this.shadowDepth = value;
429                 InvalidateClientRectangle(Rectangle.Empty);
430             }
431         }
432 
433         public Rectangle ViewPortRectangle
434         {
435             get
436             {
437                 return new Rectangle(ScrollPosition, ViewPortSize);
438             }
439         }
440 
441         public Size ViewPortSize
442         {
443             get
444             {
445                 Size viewPortSize = ClientSize;
446                 if (HScrollBar.Visible)
447                     viewPortSize.Height = Math.Max(0, viewPortSize.Height - HScrollBar.Height);
448                 if (VScrollBar.Visible)
449                     viewPortSize.Width = Math.Max(0, viewPortSize.Width - VScrollBar.Width);
450                 return viewPortSize;
451             }
452         }
453 
454         public Point ScrollPosition
455         {
456             get
457             {
458                 return new Point(HScrollBar.Value, VScrollBar.Value);
459             }
460 
461             set
462             {
463                 ScrollBar hScrollBar = HScrollBar;
464                 if (hScrollBar != null)
465                 {
466                     value.X = Math.Min(value.X, hScrollBar.Maximum - hScrollBar.LargeChange + 1);
467                     value.X = Math.Max(value.X, hScrollBar.Minimum);
468                     hScrollBar.Value = value.X;
469                 }
470 
471                 ScrollBar vScrollBar = VScrollBar;
472                 if (vScrollBar != null)
473                 {
474                     value.Y = Math.Min(value.Y, vScrollBar.Maximum - vScrollBar.LargeChange + 1);
475                     value.Y = Math.Max(value.Y, vScrollBar.Minimum);
476                     vScrollBar.Value = value.Y;
477                 }
478             }
479         }
480 
481         public bool PrintPreviewMode
482         {
483             get
484             {
485                 return (this.activeLayout == ((WorkflowPrintDocument)PrintDocument).PrintPreviewLayout);
486             }
487 
488             set
489             {
490                 if (PrintPreviewMode == value)
491                     return;
492 
493                 if (value && PrinterSettings.InstalledPrinters.Count == 0)
494                 {
495                     DesignerHelpers.ShowError(this, DR.GetString(DR.ThereIsNoPrinterInstalledErrorMessage));
496                     value = false;
497                 }
498 
499                 ActiveLayout = (value) ? ((WorkflowPrintDocument)PrintDocument).PrintPreviewLayout : DefaultLayout;
500 
501                 if (this.commandSet != null)
502                     this.commandSet.UpdatePageLayoutCommands(true);
503 
504                 if (PrintPreviewMode)
505                 {
506                     this.prePreviewZoom = Zoom;
507                     this.prePreviewScroll = ScrollPosition;
508                     Zoom = 40;
509                 }
510                 else
511                 {
512                     Zoom = this.prePreviewZoom;
513                     ScrollPosition = this.prePreviewScroll;
514                 }
515             }
516         }
517 
518         public PrintDocument PrintDocument
519         {
520             get
521             {
522                 if (this.printDocument == null)
523                     this.printDocument = new WorkflowPrintDocument(this);
524 
525                 return this.printDocument;
526             }
527         }
528 
529         public event EventHandler Idle
530         {
531             add
532             {
533                 //Add the listener to our list
534                 this.idleEventListeners += value;
535 
536                 if (this.idleEventHandler == null)
537                 {
538                     this.idleEventHandler = new EventHandler(OnWorkflowIdle);
539 
540                     Form host = TopLevelControl as Form;
541                     if (!Application.MessageLoop || (host != null && host.Modal))
542                         WorkflowTimer.Default.Subscribe(100, this.idleEventHandler);
543                     else
544                         Application.Idle += this.idleEventHandler;
545                 }
546             }
547 
548             remove
549             {
550                 this.idleEventListeners -= value;
551 
552                 if (this.idleEventHandler != null && this.idleEventListeners == null)
553                 {
554                     Form host = TopLevelControl as Form;
555                     if (host != null && host.Modal)
556                         WorkflowTimer.Default.Unsubscribe(this.idleEventHandler);
557                     else
558                         Application.Idle -= this.idleEventHandler;
559 
560                     this.idleEventHandler = null;
561                 }
562             }
563         }
564 
565         public HScrollBar HScrollBar
566         {
567             get
568             {
569                 return this.hScrollBar;
570             }
571         }
572 
573         public VScrollBar VScrollBar
574         {
575             get
576             {
577                 return this.vScrollBar;
578             }
579         }
580 
581         public bool EnableFitToScreen
582         {
583             get
584             {
585                 return (this.fitAllAction != null);
586             }
587 
588             set
589             {
590                 if (EnableFitToScreen == value)
591                     return;
592 
593                 if (value)
594                 {
595                     if (this.fitAllAction == null)
596                         this.fitAllAction = CreateDynamicAction();
597                 }
598                 else
599                 {
600                     if (this.fitAllAction != null)
601                     {
602                         this.fitAllAction.Dispose();
603                         this.fitAllAction = null;
604                     }
605                 }
606 
607                 InvalidateClientRectangle(Rectangle.Empty);
608             }
609         }
610         #endregion
611 
612         #region Protected Properties
613         #endregion
614 
615         #region Private Properties
616         internal bool DragDropInProgress
617         {
618             get
619             {
620                 return this.dragDropInProgress;
621             }
622         }
623 
624         internal bool ShowToolContainer
625         {
626             get
627             {
628                 return (this.toolContainer != null);
629             }
630 
631             set
632             {
633                 if (ShowToolContainer == value)
634                     return;
635 
636                 try
637                 {
638                     SuspendLayout();
639 
640                     if (value)
641                     {
642                         this.toolContainer = new TabControl(DockStyle.Right, AnchorAlignment.Far);
643                         Controls.Add(this.toolContainer);
644                         EnsureScrollBars(this.hScrollBar, this.toolContainer.ScrollBar as VScrollBar);
645 
646                         string[,] tabButtonInfo = new string[/*Caption Resource ID*/, /*Bitmap Resource ID*/] { { "MultipageLayoutCaption", "MultipageLayout" }, { "ZoomCaption", "Zoom" }, { "PanCaption", "AutoPan" } };
647                         for (int i = 0; i < tabButtonInfo.GetLength(0); i++)
648                         {
649                             Bitmap tabImage = DR.GetImage(tabButtonInfo[i, 1]) as Bitmap;
650                             string buttonCaption = DR.GetString(tabButtonInfo[i, 0]);
651                             this.toolContainer.TabStrip.Tabs.Add(new ItemInfo(i + 1, tabImage, buttonCaption));
652                         }
653 
654                         this.toolContainer.TabStrip.TabChange += new SelectionChangeEventHandler<TabSelectionChangeEventArgs>(OnTabChange);
655                         if (this.commandSet != null)
656                         {
657                             this.commandSet.UpdatePageLayoutCommands(true);
658                             this.commandSet.UpdateZoomCommands(true);
659                             this.commandSet.UpdatePanCommands(true);
660                         }
661                     }
662                     else
663                     {
664                         this.toolContainer.TabStrip.TabChange -= new SelectionChangeEventHandler<TabSelectionChangeEventArgs>(OnTabChange);
665                         this.toolContainer.TabStrip.Tabs.Clear();
666 
667                         Controls.Remove(this.toolContainer);
668                         this.toolContainer.Dispose();
669                         this.toolContainer = null;
670 
671                         EnsureScrollBars(this.hScrollBar, new VScrollBar());
672                     }
673                 }
674                 finally
675                 {
676                     ResumeLayout(true);
677                 }
678             }
679         }
680 
681         internal HitTestInfo MessageHitTestContext
682         {
683             get
684             {
685                 return this.messageHitTestContexts.Peek();
686             }
687         }
688 
689         internal WorkflowLayout ActiveLayout
690         {
691             get
692             {
693                 return this.activeLayout;
694             }
695 
696             set
697             {
698                 Debug.Assert(value != null);
699                 if (value == null)
700                     throw new ArgumentNullException("Layout cannot be null!");
701 
702                 Cursor cursor = Cursor.Current;
703                 try
704                 {
705                     Cursor.Current = Cursors.WaitCursor;
706 
707                     this.activeLayout = value;
708                     if (this.activeLayout != ((WorkflowPrintDocument)PrintDocument).PrintPreviewLayout)
709                         DefaultLayout = this.activeLayout;
710 
711                     base.PerformLayout();
712                     if (this.commandSet != null)
713                         this.commandSet.UpdatePageLayoutCommands(true);
714                 }
715                 finally
716                 {
717                     Cursor.Current = cursor;
718                 }
719             }
720         }
721 
722         private WorkflowLayout DefaultLayout
723         {
724             get
725             {
726                 if (this.defaultLayout == null)
727                     this.defaultLayout = new WorkflowRootLayout(this);
728                 return this.defaultLayout;
729             }
730 
731             set
732             {
733                 if (value == null)
734                     throw new ArgumentNullException(DR.GetString(DR.Error_WorkflowLayoutNull));
735 
736                 if (this.defaultLayout == value)
737                     return;
738 
739                 if (this.defaultLayout != null)
740                     this.defaultLayout.Dispose();
741 
742                 this.defaultLayout = value;
743             }
744         }
745 
746         private float ScaleZoomFactor
747         {
748             get
749             {
750                 return (this.zoomLevel * this.activeLayout.Scaling);
751             }
752         }
753         #endregion
754 
755         #region Public Methods
AddDesignerMessageFilter(WorkflowDesignerMessageFilter designerMessageFilter)756         public void AddDesignerMessageFilter(WorkflowDesignerMessageFilter designerMessageFilter)
757         {
758             if (designerMessageFilter == null)
759                 throw new ArgumentNullException("designerMessageFilter");
760 
761             if (Capture)
762                 Capture = false;
763 
764             this.customMessageFilters.Insert(0, designerMessageFilter);
765             designerMessageFilter.SetParentView(this);
766         }
767 
RemoveDesignerMessageFilter(WorkflowDesignerMessageFilter designerMessageFilter)768         public void RemoveDesignerMessageFilter(WorkflowDesignerMessageFilter designerMessageFilter)
769         {
770             if (designerMessageFilter == null)
771                 throw new ArgumentNullException("designerMessageFilter");
772 
773             if (this.customMessageFilters.Contains(designerMessageFilter))
774             {
775                 if (Capture)
776                     Capture = false;
777 
778                 this.customMessageFilters.Remove(designerMessageFilter);
779                 ((IDisposable)designerMessageFilter).Dispose();
780             }
781         }
782 
ShowInPlaceToolTip(string toolTipText, Rectangle toolTipRectangle)783         public void ShowInPlaceToolTip(string toolTipText, Rectangle toolTipRectangle)
784         {
785             if (toolTipText == null)
786                 throw new ArgumentNullException("toolTipText");
787 
788             if (toolTipRectangle.IsEmpty)
789                 throw new ArgumentException(SR.GetString(SR.Error_EmptyToolTipRectangle));
790 
791             this.workflowToolTip.SetText(toolTipText, toolTipRectangle);
792         }
793 
ShowInfoTip(string text)794         public void ShowInfoTip(string text)
795         {
796             if (text == null)
797                 throw new ArgumentNullException("text");
798 
799             this.workflowToolTip.SetText(String.Empty, text);
800         }
801 
ShowInfoTip(string title, string text)802         public void ShowInfoTip(string title, string text)
803         {
804             if (title == null)
805                 throw new ArgumentNullException("title");
806 
807             if (text == null)
808                 throw new ArgumentNullException("text");
809 
810             this.workflowToolTip.SetText(title, text);
811         }
812 
EnsureVisible(object selectableObject)813         public void EnsureVisible(object selectableObject)
814         {
815             if (selectableObject == null)
816                 throw new ArgumentNullException("selectableObject");
817 
818             // make sure that all the parents are expanded
819             Activity activity = selectableObject as Activity;
820             while (activity != null)
821             {
822                 ActivityDesigner activityDesigner = ActivityDesigner.GetDesigner(activity);
823                 CompositeActivityDesigner parentDesigner = activityDesigner.ParentDesigner;
824                 if (parentDesigner != null)
825                 {
826                     if (activityDesigner != null)
827                         parentDesigner.EnsureVisibleContainedDesigner(activityDesigner);
828                     activity = parentDesigner.Activity;
829                 }
830                 else
831                 {
832                     activity = null;
833                 }
834             }
835 
836             //this is to handle the case when we call ensure visible of a scope which currently has
837             //activity from the secondary flow selected. instead we should always switch to the main flow
838             activity = selectableObject as Activity;
839             if (activity != null)
840             {
841                 CompositeActivityDesigner compositeDesigner = ActivityDesigner.GetDesigner(activity) as CompositeActivityDesigner;
842                 if (compositeDesigner != null)
843                     compositeDesigner.EnsureVisibleContainedDesigner(compositeDesigner);
844             }
845 
846             PerformLayout(false);
847 
848             if (this.ensureVisibleEventHandler == null)
849             {
850                 this.ensureVisibleEventHandler = new EventHandler(OnEnsureVisible);
851                 Idle += this.ensureVisibleEventHandler;
852             }
853         }
854 
PerformLayout(bool immediateUpdate)855         public void PerformLayout(bool immediateUpdate)
856         {
857             if (immediateUpdate)
858             {
859                 if (this.layoutEventHandler != null)
860                 {
861                     Idle -= this.layoutEventHandler;
862                     this.layoutEventHandler = null;
863                 }
864                 base.PerformLayout(); //invalidate rectangle really cares for the this.layoutEventHandler being null
865             }
866             else if (this.layoutEventHandler == null)
867             {
868                 this.layoutEventHandler = new EventHandler(OnPerformLayout);
869                 Idle += this.layoutEventHandler;
870             }
871         }
872 
SaveViewState(Stream viewState)873         public void SaveViewState(Stream viewState)
874         {
875             if (viewState == null)
876                 throw new ArgumentNullException("viewState");
877 
878             IDesignerHost designerHost = (IDesignerHost)GetService(typeof(IDesignerHost));
879             if (designerHost == null)
880                 throw new Exception(SR.GetString(SR.General_MissingService, typeof(IDesignerHost).FullName));
881 
882             BinaryWriter writer = new BinaryWriter(viewState);
883 
884             // write workflow properties
885             writer.Write(this.PrintPreviewMode);
886             writer.Write(this.Zoom);
887 
888             // write components
889             DesignerHelpers.SerializeDesignerStates(designerHost, writer);
890 
891             // write scroll position
892             writer.Write(this.ScrollPosition.X);
893             writer.Write(this.ScrollPosition.Y);
894         }
895 
LoadViewState(Stream viewState)896         public void LoadViewState(Stream viewState)
897         {
898             if (viewState == null)
899                 throw new ArgumentNullException("viewState");
900 
901             bool outdated = false;
902             Point scrollPosition = new Point(0, 0);
903 
904             IDesignerHost designerHost = (IDesignerHost)GetService(typeof(IDesignerHost));
905             if (designerHost == null)
906                 throw new Exception(SR.GetString(SR.General_MissingService, typeof(IDesignerHost).FullName));
907 
908             viewState.Position = 0;
909 
910             BinaryReader reader = new BinaryReader(viewState);
911 
912             // read workflow properties
913             this.PrintPreviewMode = reader.ReadBoolean();
914             this.Zoom = reader.ReadInt32();
915             try
916             {
917                 // get activities
918                 outdated = DesignerHelpers.DeserializeDesignerStates(designerHost, reader);
919 
920                 // we will apply the scrolling only if if there is perfect match
921                 // between the components in the workflow and the persisted data.
922                 // It might be different if files were updated outside of VS, or if
923                 // VS crashes.
924                 if (!outdated)
925                 {
926                     scrollPosition.X = reader.ReadInt32();
927                     scrollPosition.Y = reader.ReadInt32();
928                 }
929             }
930             finally
931             {
932                 // flush the layout to apply the new settings, this will set the scrollers extents
933                 base.PerformLayout();
934                 this.ScrollPosition = scrollPosition;
935             }
936         }
937 
938         /// <summary>
939         /// Changes zoom level on the design surface such that the entire workflow is displayed in the view
940         /// </summary>
FitToScreenSize()941         public void FitToScreenSize()
942         {
943             if (HScrollBar.Maximum > ViewPortSize.Width || VScrollBar.Maximum > ViewPortSize.Height)
944             {
945                 int newZoom = (int)(100.0f / ActiveLayout.Scaling * Math.Min((float)ViewPortSize.Width / (float)ActiveLayout.Extent.Width, (float)ViewPortSize.Height / (float)ActiveLayout.Extent.Height));
946                 Zoom = Math.Min(Math.Max(newZoom, AmbientTheme.MinZoom), AmbientTheme.MaxZoom);
947             }
948         }
949 
950         /// <summary>
951         /// Sets the zoom level to 100% so that the workflow size is restored to actial workflow size
952         /// </summary>
FitToWorkflowSize()953         public void FitToWorkflowSize()
954         {
955             if (Zoom != 100)
956                 Zoom = 100;
957         }
958 
959         /// <summary>
960         /// Saves workflow as image to a file based on the format specified
961         /// </summary>
962         /// <param name="imageFile">Path to file where to save the image</param>
963         /// <param name="imageFormat">Format in which to save the image</param>
SaveWorkflowImage(string imageFile, ImageFormat imageFormat)964         public void SaveWorkflowImage(string imageFile, ImageFormat imageFormat)
965         {
966             if (imageFile == null)
967                 throw new ArgumentNullException("imageFile");
968 
969             if (imageFormat == null)
970                 throw new ArgumentNullException("imageFormat");
971 
972             Bitmap workflowBitmap = TakeWorkflowSnapShot();
973             if (workflowBitmap != null)
974             {
975                 workflowBitmap.Save(imageFile, imageFormat);
976                 workflowBitmap.Dispose();
977             }
978         }
979 
980         /// <summary>
981         /// Saves workflow as image to a stream based on encoding specified
982         /// </summary>
983         /// <param name="stream">Stream where to save the workflow</param>
984         /// <param name="imageFormat">Format in which to save the image</param>
SaveWorkflowImage(Stream stream, ImageFormat imageFormat)985         public void SaveWorkflowImage(Stream stream, ImageFormat imageFormat)
986         {
987             if (stream == null)
988                 throw new ArgumentNullException("stream");
989 
990             if (imageFormat == null)
991                 throw new ArgumentNullException("imageFormat");
992 
993             Bitmap workflowBitmap = TakeWorkflowSnapShot();
994             if (workflowBitmap != null)
995             {
996                 workflowBitmap.Save(stream, imageFormat);
997                 workflowBitmap.Dispose();
998             }
999         }
1000 
1001         /// <summary>
1002         /// Stores the workflow image to clipboard.
1003         /// </summary>
SaveWorkflowImageToClipboard()1004         public void SaveWorkflowImageToClipboard()
1005         {
1006             Bitmap workflowBitmap = TakeWorkflowSnapShot();
1007             if (workflowBitmap != null)
1008             {
1009                 Clipboard.SetDataObject(workflowBitmap, true);
1010                 workflowBitmap.Dispose();
1011             }
1012         }
1013         #endregion
1014 
1015         #region Protected Methods
1016 
1017         #region Overridden Methods handling UI events
1018         #region Drawing
OnPaint(PaintEventArgs e)1019         protected override void OnPaint(PaintEventArgs e)
1020         {
1021             base.OnPaint(e);
1022 
1023             //We set the highest quality interpolation so that we do not loose the image quality
1024             GraphicsContainer graphicsState = e.Graphics.BeginContainer();
1025             e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
1026             e.Graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
1027             e.Graphics.CompositingQuality = CompositingQuality.HighQuality;
1028 
1029             bool takeWorkflowSnapShot = (this.viewPortBitmap == null || this.viewPortBitmap.Size != ViewPortSize);
1030             if (takeWorkflowSnapShot)
1031             {
1032                 if (this.viewPortBitmap != null)
1033                     this.viewPortBitmap.Dispose();
1034                 this.viewPortBitmap = new Bitmap(Math.Max(1, ViewPortSize.Width), Math.Max(1, ViewPortSize.Height), e.Graphics);
1035             }
1036 
1037             //Create viewport information and take the workflow snapshot before passing on the information to the active layout
1038             ViewPortData viewPortData = new ViewPortData();
1039             viewPortData.LogicalViewPort = ClientRectangleToLogical(new Rectangle(Point.Empty, ViewPortSize));
1040             viewPortData.MemoryBitmap = this.viewPortBitmap;
1041             viewPortData.Scaling = new SizeF(ScaleZoomFactor, ScaleZoomFactor);
1042             viewPortData.Translation = ScrollPosition;
1043             viewPortData.ShadowDepth = new Size(this.shadowDepth, this.shadowDepth);
1044             viewPortData.ViewPortSize = ViewPortSize;
1045 
1046             //capture the workflow onto in-memory bitmap
1047             if (this.layoutEventHandler == null || takeWorkflowSnapShot)
1048                 WorkflowView.TakeWorkflowSnapShot(this, viewPortData);
1049 
1050             //copy workflow from the bitmap onto corresponding pages on the screen
1051             try
1052             {
1053                 this.activeLayout.OnPaintWorkflow(e, viewPortData);
1054             }
1055             catch (Exception ex)
1056             {
1057                 //If a layout throws an exception then we will not draw the layout
1058                 //
1059                 Debug.WriteLine(ex);
1060             }
1061 
1062             //If any of the message filters throws an exception we continue to draw
1063             using (WorkflowMessageDispatchData dispatchData = new WorkflowMessageDispatchData(this, EventArgs.Empty))
1064             {
1065                 foreach (WorkflowDesignerMessageFilter filter in dispatchData.Filters)
1066                 {
1067                     try
1068                     {
1069                         if (((IWorkflowDesignerMessageSink)filter).OnPaintWorkflowAdornments(e, ViewPortRectangle))
1070                             break;
1071                     }
1072                     catch (Exception ex)
1073                     {
1074                         //Ignore the filter throwing the exception and continue to function
1075                         Debug.WriteLine(ex);
1076                     }
1077                 }
1078             }
1079 
1080             e.Graphics.EndContainer(graphicsState);
1081 
1082             e.Graphics.FillRectangle(SystemBrushes.Control, new Rectangle(Width - SystemInformation.VerticalScrollBarWidth, Height - SystemInformation.HorizontalScrollBarHeight, SystemInformation.VerticalScrollBarWidth, SystemInformation.HorizontalScrollBarHeight));
1083         }
1084 
OnZoomChanged()1085         protected virtual void OnZoomChanged()
1086         {
1087             if (this.ZoomChanged != null)
1088                 this.ZoomChanged(this, EventArgs.Empty);
1089         }
1090 
OnRootDesignerChanged()1091         protected virtual void OnRootDesignerChanged()
1092         {
1093             if (this.RootDesignerChanged != null)
1094                 this.RootDesignerChanged(this, EventArgs.Empty);
1095         }
1096         #endregion
1097 
1098         #region Mouse Events
OnMouseDown(MouseEventArgs e)1099         protected override void OnMouseDown(MouseEventArgs e)
1100         {
1101             base.OnMouseDown(e);
1102 
1103             using (WorkflowMessageDispatchData dispatchData = new WorkflowMessageDispatchData(this, e))
1104             {
1105                 foreach (WorkflowDesignerMessageFilter filter in dispatchData.Filters)
1106                 {
1107                     if (((IWorkflowDesignerMessageSink)filter).OnMouseDown(e))
1108                         break;
1109                 }
1110             }
1111         }
1112 
OnMouseMove(MouseEventArgs e)1113         protected override void OnMouseMove(MouseEventArgs e)
1114         {
1115             base.OnMouseMove(e);
1116 
1117             using (WorkflowMessageDispatchData dispatchData = new WorkflowMessageDispatchData(this, e))
1118             {
1119                 foreach (WorkflowDesignerMessageFilter filter in dispatchData.Filters)
1120                 {
1121                     if (((IWorkflowDesignerMessageSink)filter).OnMouseMove(e))
1122                         break;
1123                 }
1124             }
1125         }
1126 
OnMouseUp(MouseEventArgs e)1127         protected override void OnMouseUp(MouseEventArgs e)
1128         {
1129             base.OnMouseUp(e);
1130 
1131             using (WorkflowMessageDispatchData dispatchData = new WorkflowMessageDispatchData(this, e))
1132             {
1133                 foreach (WorkflowDesignerMessageFilter filter in dispatchData.Filters)
1134                 {
1135                     if (((IWorkflowDesignerMessageSink)filter).OnMouseUp(e))
1136                         break;
1137                 }
1138             }
1139         }
1140 
OnMouseDoubleClick(MouseEventArgs e)1141         protected override void OnMouseDoubleClick(MouseEventArgs e)
1142         {
1143             base.OnMouseDoubleClick(e);
1144 
1145             using (WorkflowMessageDispatchData dispatchData = new WorkflowMessageDispatchData(this, e))
1146             {
1147                 foreach (WorkflowDesignerMessageFilter filter in dispatchData.Filters)
1148                 {
1149                     if (((IWorkflowDesignerMessageSink)filter).OnMouseDoubleClick(e))
1150                         break;
1151                 }
1152             }
1153         }
1154 
OnMouseEnter(EventArgs e)1155         protected override void OnMouseEnter(EventArgs e)
1156         {
1157             base.OnMouseEnter(e);
1158 
1159             Point clientPoint = PointToClient(Control.MousePosition);
1160             MouseEventArgs eventArgs = new MouseEventArgs(Control.MouseButtons, 1, clientPoint.X, clientPoint.Y, 0);
1161 
1162             using (WorkflowMessageDispatchData dispatchData = new WorkflowMessageDispatchData(this, eventArgs))
1163             {
1164                 foreach (WorkflowDesignerMessageFilter filter in dispatchData.Filters)
1165                 {
1166                     if (((IWorkflowDesignerMessageSink)filter).OnMouseEnter(eventArgs))
1167                         break;
1168                 }
1169             }
1170         }
1171 
OnMouseHover(EventArgs e)1172         protected override void OnMouseHover(EventArgs e)
1173         {
1174             base.OnMouseHover(e);
1175 
1176             Point clientPoint = PointToClient(Control.MousePosition);
1177             MouseEventArgs eventArgs = new MouseEventArgs(Control.MouseButtons, 1, clientPoint.X, clientPoint.Y, 0);
1178 
1179             using (WorkflowMessageDispatchData dispatchData = new WorkflowMessageDispatchData(this, eventArgs))
1180             {
1181                 foreach (WorkflowDesignerMessageFilter filter in dispatchData.Filters)
1182                 {
1183                     if (((IWorkflowDesignerMessageSink)filter).OnMouseHover(eventArgs))
1184                         break;
1185                 }
1186             }
1187         }
1188 
OnMouseLeave(EventArgs e)1189         protected override void OnMouseLeave(EventArgs e)
1190         {
1191             base.OnMouseLeave(e);
1192 
1193             using (WorkflowMessageDispatchData dispatchData = new WorkflowMessageDispatchData(this, EventArgs.Empty))
1194             {
1195                 foreach (WorkflowDesignerMessageFilter filter in dispatchData.Filters)
1196                 {
1197                     if (((IWorkflowDesignerMessageSink)filter).OnMouseLeave())
1198                         break;
1199                 }
1200             }
1201         }
1202 
OnMouseCaptureChanged(EventArgs e)1203         protected override void OnMouseCaptureChanged(EventArgs e)
1204         {
1205             base.OnMouseCaptureChanged(e);
1206 
1207             using (WorkflowMessageDispatchData dispatchData = new WorkflowMessageDispatchData(this, EventArgs.Empty))
1208             {
1209                 foreach (WorkflowDesignerMessageFilter filter in dispatchData.Filters)
1210                 {
1211                     if (((IWorkflowDesignerMessageSink)filter).OnMouseCaptureChanged())
1212                         break;
1213                 }
1214             }
1215         }
1216 
OnMouseWheel(MouseEventArgs e)1217         protected override void OnMouseWheel(MouseEventArgs e)
1218         {
1219             base.OnMouseWheel(e);
1220 
1221             using (WorkflowMessageDispatchData dispatchData = new WorkflowMessageDispatchData(this, e))
1222             {
1223                 foreach (WorkflowDesignerMessageFilter filter in dispatchData.Filters)
1224                 {
1225                     if (((IWorkflowDesignerMessageSink)filter).OnMouseWheel(e))
1226                         break;
1227                 }
1228             }
1229         }
1230         #endregion
1231 
1232         #region Keyboard Events
OnKeyDown(KeyEventArgs e)1233         protected override void OnKeyDown(KeyEventArgs e)
1234         {
1235             using (WorkflowMessageDispatchData dispatchData = new WorkflowMessageDispatchData(this, e))
1236             {
1237                 foreach (WorkflowDesignerMessageFilter filter in dispatchData.Filters)
1238                 {
1239                     if (((IWorkflowDesignerMessageSink)filter).OnKeyDown(e))
1240                         break;
1241                 }
1242             }
1243 
1244             if (!e.Handled)
1245                 base.OnKeyDown(e);
1246         }
1247 
OnKeyUp(KeyEventArgs e)1248         protected override void OnKeyUp(KeyEventArgs e)
1249         {
1250             using (WorkflowMessageDispatchData dispatchData = new WorkflowMessageDispatchData(this, e))
1251             {
1252                 foreach (WorkflowDesignerMessageFilter filter in dispatchData.Filters)
1253                 {
1254                     if (((IWorkflowDesignerMessageSink)filter).OnKeyUp(e))
1255                         break;
1256                 }
1257             }
1258 
1259             if (!e.Handled)
1260                 base.OnKeyUp(e);
1261         }
1262         #endregion
1263 
1264         #region Layouting Events
OnLayout(LayoutEventArgs levent)1265         protected override void OnLayout(LayoutEventArgs levent)
1266         {
1267             base.OnLayout(levent);
1268 
1269             ScrollBar hScrollBar = HScrollBar;
1270             ScrollBar vScrollBar = VScrollBar;
1271 
1272             if (Controls.Contains(hScrollBar))
1273                 hScrollBar.Bounds = new Rectangle(0, Math.Max(0, Height - SystemInformation.HorizontalScrollBarHeight), Math.Max(Width - ((vScrollBar.Visible) ? SystemInformation.VerticalScrollBarWidth : 0), 0), SystemInformation.HorizontalScrollBarHeight);
1274 
1275             if (Controls.Contains(vScrollBar))
1276                 vScrollBar.Bounds = new Rectangle(Math.Max(0, Width - SystemInformation.VerticalScrollBarWidth), 0, SystemInformation.VerticalScrollBarWidth, Math.Max(Height - ((hScrollBar.Visible) ? SystemInformation.HorizontalScrollBarHeight : 0), 0));
1277 
1278             if (this.toolContainer != null)
1279             {
1280                 this.toolContainer.Location = new Point(Width - this.toolContainer.Width, 0);
1281                 this.toolContainer.Height = Height - ((hScrollBar.Visible) ? hScrollBar.Height : 0);
1282             }
1283 
1284             using (WorkflowMessageDispatchData dispatchData = new WorkflowMessageDispatchData(this, levent))
1285             {
1286                 foreach (WorkflowDesignerMessageFilter filter in dispatchData.Filters)
1287                     ((IWorkflowDesignerMessageSink)filter).OnLayout(levent);
1288             }
1289 
1290             //Layout the designers
1291             using (Graphics graphics = CreateGraphics())
1292             {
1293                 this.activeLayout.Update(graphics, WorkflowLayout.LayoutUpdateReason.LayoutChanged);
1294 
1295                 if (this.rootDesigner != null)
1296                     this.rootDesigner.Location = this.activeLayout.RootDesignerAlignment;
1297             }
1298 
1299             //Update the scroll range and redraw
1300             UpdateScrollRange();
1301             InvalidateClientRectangle(Rectangle.Empty);
1302         }
1303         #endregion
1304 
1305         #region DragDrop Events
OnDragEnter(DragEventArgs dragEventArgs)1306         protected override void OnDragEnter(DragEventArgs dragEventArgs)
1307         {
1308             base.OnDragEnter(dragEventArgs);
1309 
1310             this.dragDropInProgress = true;
1311 
1312             using (WorkflowMessageDispatchData dispatchData = new WorkflowMessageDispatchData(this, dragEventArgs))
1313             {
1314                 foreach (WorkflowDesignerMessageFilter filter in dispatchData.Filters)
1315                 {
1316                     if (((IWorkflowDesignerMessageSink)filter).OnDragEnter(dragEventArgs))
1317                         break;
1318                 }
1319             }
1320         }
1321 
OnDragOver(DragEventArgs dragEventArgs)1322         protected override void OnDragOver(DragEventArgs dragEventArgs)
1323         {
1324             base.OnDragOver(dragEventArgs);
1325 
1326             using (WorkflowMessageDispatchData dispatchData = new WorkflowMessageDispatchData(this, dragEventArgs))
1327             {
1328                 foreach (WorkflowDesignerMessageFilter filter in dispatchData.Filters)
1329                 {
1330                     if (((IWorkflowDesignerMessageSink)filter).OnDragOver(dragEventArgs))
1331                         break;
1332                 }
1333             }
1334         }
1335 
OnDragLeave(EventArgs e)1336         protected override void OnDragLeave(EventArgs e)
1337         {
1338             base.OnDragLeave(e);
1339 
1340             using (WorkflowMessageDispatchData dispatchData = new WorkflowMessageDispatchData(this, EventArgs.Empty))
1341             {
1342                 foreach (WorkflowDesignerMessageFilter filter in dispatchData.Filters)
1343                 {
1344                     if (((IWorkflowDesignerMessageSink)filter).OnDragLeave())
1345                         break;
1346                 }
1347             }
1348 
1349             this.dragDropInProgress = false;
1350         }
1351 
OnDragDrop(DragEventArgs dragEventArgs)1352         protected override void OnDragDrop(DragEventArgs dragEventArgs)
1353         {
1354             base.OnDragDrop(dragEventArgs);
1355 
1356             using (WorkflowMessageDispatchData dispatchData = new WorkflowMessageDispatchData(this, dragEventArgs))
1357             {
1358                 foreach (WorkflowDesignerMessageFilter filter in dispatchData.Filters)
1359                 {
1360                     if (((IWorkflowDesignerMessageSink)filter).OnDragDrop(dragEventArgs))
1361                         break;
1362                 }
1363             }
1364 
1365             this.dragDropInProgress = false;
1366         }
1367 
OnGiveFeedback(GiveFeedbackEventArgs gfbevent)1368         protected override void OnGiveFeedback(GiveFeedbackEventArgs gfbevent)
1369         {
1370             base.OnGiveFeedback(gfbevent);
1371 
1372             using (WorkflowMessageDispatchData dispatchData = new WorkflowMessageDispatchData(this, gfbevent))
1373             {
1374                 foreach (WorkflowDesignerMessageFilter filter in dispatchData.Filters)
1375                 {
1376                     if (((IWorkflowDesignerMessageSink)filter).OnGiveFeedback(gfbevent))
1377                         break;
1378                 }
1379             }
1380         }
1381 
OnQueryContinueDrag(QueryContinueDragEventArgs qcdevent)1382         protected override void OnQueryContinueDrag(QueryContinueDragEventArgs qcdevent)
1383         {
1384             base.OnQueryContinueDrag(qcdevent);
1385 
1386             using (WorkflowMessageDispatchData dispatchData = new WorkflowMessageDispatchData(this, qcdevent))
1387             {
1388                 foreach (WorkflowDesignerMessageFilter filter in dispatchData.Filters)
1389                 {
1390                     if (((IWorkflowDesignerMessageSink)filter).OnQueryContinueDrag(qcdevent))
1391                         break;
1392                 }
1393             }
1394         }
1395         #endregion
1396 
1397         #region General Events
1398         //Handle context menus here reason being it can come from mouse r button click
1399         //or shift+F10, or there might be other keys too
1400         //We need to handle the WndProc and not the OnNotifyMessage because we need to set
1401         //the m.Result to handled (IntPtr.Zero) and dont let the base class see the message at all
1402         //see WinOE #787 "The keyboard "key" to launch the context menu launches the menu at 0,0"
1403         [UIPermission(SecurityAction.Assert, Window = UIPermissionWindow.AllWindows)]
1404         [SuppressMessage("Microsoft.Security", "CA2106", Justification = "This is SecurityCritical, therefore not callable from partial trust code.")]
WndProc(ref Message m)1405         protected override void WndProc(ref Message m)
1406         {
1407             using (WorkflowMessageDispatchData dispatchData = new WorkflowMessageDispatchData(this, EventArgs.Empty))
1408             {
1409                 foreach (WorkflowDesignerMessageFilter filter in dispatchData.Filters)
1410                 {
1411                     if (((IWorkflowDesignerMessageSink)filter).ProcessMessage(m))
1412                         break;
1413                 }
1414 
1415                 const int WM_CONTEXTMENU = 0x007B;
1416                 if (m.Msg == WM_CONTEXTMENU)
1417                 {
1418                     int LParam = (int)m.LParam;
1419                     Point location = (LParam != -1) ? new Point(LParam) : Control.MousePosition;
1420 
1421                     foreach (WorkflowDesignerMessageFilter filter in dispatchData.Filters)
1422                     {
1423                         if (((IWorkflowDesignerMessageSink)filter).OnShowContextMenu(location))
1424                             break;
1425                     }
1426 
1427                     //mark the message handled
1428                     m.Result = IntPtr.Zero;
1429                     //dont pass the message to the base but return immediatly
1430                     return;
1431                 }
1432             }
1433 
1434             if (this.workflowToolTip != null && m.Msg == NativeMethods.WM_NOTIFY)
1435                 this.workflowToolTip.RelayParentNotify(ref m);
1436 
1437             try
1438             {
1439                 if (m.Result == IntPtr.Zero)
1440                     base.WndProc(ref m);
1441             }
1442             catch (Exception e)
1443             {
1444                 if (e != CheckoutException.Canceled)
1445                     DesignerHelpers.ShowError(this, e);
1446             }
1447         }
1448 
OnControlAdded(ControlEventArgs e)1449         protected override void OnControlAdded(ControlEventArgs e)
1450         {
1451             if (e.Control != VScrollBar && e.Control != HScrollBar && e.Control != this.toolContainer)
1452                 throw new InvalidOperationException(SR.GetString(SR.Error_InsertingChildControls));
1453         }
1454 
CreateAccessibilityInstance()1455         protected override AccessibleObject CreateAccessibilityInstance()
1456         {
1457             return new WorkflowViewAccessibleObject(this);
1458         }
1459         #endregion
1460 
1461         #endregion
1462 
1463         #endregion
1464 
1465         #region Private Methods
OnWorkflowIdle(object sender, EventArgs e)1466         private void OnWorkflowIdle(object sender, EventArgs e)
1467         {
1468             if (this.idleEventListeners != null)
1469                 this.idleEventListeners(this, e);
1470         }
1471 
UpdateLayout()1472         private void UpdateLayout()
1473         {
1474             if (this.layoutEventHandler != null)
1475             {
1476                 PerformLayout(true);
1477                 InvalidateClientRectangle(Rectangle.Empty);
1478             }
1479         }
1480 
OnCommandKey(KeyEventArgs e)1481         internal void OnCommandKey(KeyEventArgs e)
1482         {
1483             this.OnKeyDown(e);
1484             this.OnKeyUp(e);
1485         }
1486 
OnSelectionChanged(object sender, EventArgs e)1487         private void OnSelectionChanged(object sender, EventArgs e)
1488         {
1489             if (this.commandSet != null)
1490                 this.commandSet.UpdateCommandSet();
1491 
1492             //Make sure that the ensure visible also works when the component is selected
1493             //from property browser dropdown
1494             //Make sure that when there is a selection change using the property browser
1495             //drop down we make sure that the designer associated with component selected by the user in the dropdown
1496             //is made visible.
1497             //To enable this functionality please note that selection change is not a good event as it will get
1498             //fired in multiple cases, instead we should add a event in extended ui service which will do this and move
1499             //the following code in the event handler of that event
1500             //Ref Bug#3925
1501 
1502             if (RootDesigner != null && RootDesigner.Activity != null)
1503             {
1504                 ISelectionService selectionService = GetService(typeof(ISelectionService)) as ISelectionService;
1505                 if (selectionService != null && selectionService.GetComponentSelected(RootDesigner.Activity))
1506                 {
1507                     IHelpService helpService = GetService(typeof(IHelpService)) as IHelpService;
1508                     if (helpService != null)
1509                         helpService.AddContextAttribute("Keyword", RootDesigner.Activity.GetType().FullName, HelpKeywordType.F1Keyword);
1510                 }
1511             }
1512         }
1513 
OnPerformLayout(object sender, EventArgs e)1514         private void OnPerformLayout(object sender, EventArgs e)
1515         {
1516             if (this.layoutEventHandler != null)
1517             {
1518                 Idle -= this.layoutEventHandler;
1519                 this.layoutEventHandler = null;
1520 
1521                 base.PerformLayout();
1522             }
1523         }
1524 
1525         //Gets the snapshot of the entire workflow
TakeWorkflowSnapShot()1526         private Bitmap TakeWorkflowSnapShot()
1527         {
1528             Bitmap bitmap = null;
1529             ActivityDesigner rootDesigner = RootDesigner;
1530             if (rootDesigner != null)
1531             {
1532                 using (Graphics graphics = CreateGraphics())
1533                 {
1534                     ViewPortData viewPortData = new ViewPortData();
1535                     viewPortData.LogicalViewPort = new Rectangle(Point.Empty, new Size(rootDesigner.Bounds.Width + 2 * DefaultWorkflowLayout.Separator.Width, rootDesigner.Bounds.Height + 2 * DefaultWorkflowLayout.Separator.Height));
1536                     viewPortData.MemoryBitmap = new Bitmap(viewPortData.LogicalViewPort.Width, viewPortData.LogicalViewPort.Height, graphics);
1537                     viewPortData.Scaling = new SizeF(1, 1);
1538                     viewPortData.Translation = Point.Empty;
1539                     viewPortData.ShadowDepth = new Size(0, 0);
1540                     viewPortData.ViewPortSize = viewPortData.LogicalViewPort.Size;
1541                     TakeWorkflowSnapShot(this, viewPortData);
1542                     bitmap = viewPortData.MemoryBitmap;
1543                 }
1544             }
1545 
1546             return bitmap;
1547         }
1548 
1549         //This function will give snapshot of what is drawn on the screen at any point of time
1550         //It will scale and translate the designers and drawing based on the viewport data
1551         //We need this function in OnPaint and taking snapshot of magnifier bitmap
1552         //At the end of this function; the ViewPortData.MemoryBitmap will contain the bitmap of the
1553         //workflow to be drawn as per layout
TakeWorkflowSnapShot(WorkflowView workflowView, ViewPortData viewPortData)1554         internal static void TakeWorkflowSnapShot(WorkflowView workflowView, ViewPortData viewPortData)
1555         {
1556             //Get the drawing canvas
1557             Bitmap memoryBitmap = viewPortData.MemoryBitmap;
1558             Debug.Assert(memoryBitmap != null);
1559 
1560             using (Graphics viewPortGraphics = Graphics.FromImage(memoryBitmap))
1561             {
1562                 //We set the highest quality interpolation so that we do not loose the image quality
1563                 viewPortGraphics.SmoothingMode = SmoothingMode.HighQuality;
1564                 viewPortGraphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
1565 
1566                 using (PaintEventArgs eventArgs = new PaintEventArgs(viewPortGraphics, viewPortData.LogicalViewPort))
1567                 {
1568                     workflowView.ActiveLayout.OnPaint(eventArgs, viewPortData);
1569                 }
1570 
1571                 //Create the scaling matrix
1572                 Matrix transformationMatrix = new Matrix();
1573                 transformationMatrix.Scale(viewPortData.Scaling.Width, viewPortData.Scaling.Height, MatrixOrder.Prepend);
1574 
1575                 //When we draw on the viewport we draw in scaled and translated.
1576                 //So that we minimize the calls to DrawImage
1577                 //Make sure that we scale down the logical view port origin in order to take care of scaling factor
1578                 //Before we select the transform factor we make sure that logicalviewport origin is scaled down
1579                 Point[] logicalViewPortOrigin = new Point[] { viewPortData.LogicalViewPort.Location };
1580                 transformationMatrix.TransformPoints(logicalViewPortOrigin);
1581 
1582                 //For performance improvement and to eliminate one extra DrawImage...we draw the designers on the viewport
1583                 //bitmap with visual depth consideration
1584                 transformationMatrix.Translate(-logicalViewPortOrigin[0].X + viewPortData.ShadowDepth.Width, -logicalViewPortOrigin[0].Y + viewPortData.ShadowDepth.Height, MatrixOrder.Append);
1585 
1586                 //Select the transform into viewport graphics.
1587                 //Viewport bitmap has the scaled and translated designers which we then map to
1588                 //the actual graphics based on page layout
1589                 viewPortGraphics.Transform = transformationMatrix;
1590 
1591                 //Draw the designers on bitmap
1592                 if (workflowView.RootDesigner != null)
1593                 {
1594                     using (Region clipRegion = new Region())
1595                     using (GraphicsPath designerPath = ActivityDesignerPaint.GetDesignerPath(workflowView.RootDesigner, false))
1596                     {
1597                         Region oldRegion = viewPortGraphics.Clip;
1598 
1599                         //First draw the grid and rectangle with the designer clip region
1600                         clipRegion.MakeEmpty();
1601                         clipRegion.Union(designerPath);
1602                         viewPortGraphics.Clip = clipRegion;
1603                         AmbientTheme ambientTheme = WorkflowTheme.CurrentTheme.AmbientTheme;
1604                         viewPortGraphics.FillRectangle(ambientTheme.BackgroundBrush, workflowView.RootDesigner.Bounds);
1605                         if (ambientTheme.ShowGrid)
1606                             ActivityDesignerPaint.DrawGrid(viewPortGraphics, workflowView.RootDesigner.Bounds);
1607                         viewPortGraphics.Clip = oldRegion;
1608 
1609                         //Then draw the root with clip region extended
1610                         try
1611                         {
1612                             using (PaintEventArgs paintEventArgs = new PaintEventArgs(viewPortGraphics, viewPortData.LogicalViewPort))
1613                             {
1614                                 ((IWorkflowDesignerMessageSink)workflowView.RootDesigner).OnPaint(paintEventArgs, viewPortData.LogicalViewPort);
1615                             }
1616                         }
1617                         catch (Exception e)
1618                         {
1619                             //Eat the exception thrown in draw
1620                             Debug.WriteLine(e);
1621                         }
1622                     }
1623                 }
1624 
1625                 //Draw all the filters
1626 
1627 
1628                 using (PaintEventArgs paintArgs = new PaintEventArgs(viewPortGraphics, workflowView.RootDesigner.Bounds))
1629                 {
1630                     using (WorkflowMessageDispatchData dispatchData = new WorkflowMessageDispatchData(workflowView, EventArgs.Empty))
1631                     {
1632                         foreach (WorkflowDesignerMessageFilter filter in dispatchData.Filters)
1633                         {
1634                             try
1635                             {
1636                                 if (((IWorkflowDesignerMessageSink)filter).OnPaint(paintArgs, viewPortData.LogicalViewPort))
1637                                     break;
1638                             }
1639                             catch (Exception e)
1640                             {
1641                                 Debug.WriteLine(e);
1642                             }
1643                         }
1644                     }
1645                 }
1646 
1647                 viewPortGraphics.Transform = new Matrix();
1648 
1649                 //Now that we have a bitmap which is bit offseted based visual depth we need to take copy of it
1650                 //This is done so as to avoid expensive DrawImage call, what I am assuming here is that time it
1651                 //will take to create a new bitmap from an existing one is less expensive in terms of speed than space
1652                 //As you just need to copy bitmap bits in memory than to perform expesive Image Drawing operation
1653                 if (!viewPortData.ShadowDepth.IsEmpty)
1654                 {
1655                     Bitmap temporaryBitmap = new Bitmap(memoryBitmap);
1656 
1657                     //THEMETODO: WE JUST NEED TO GRAYSCALE THIS, RATHER THAN DRAWING A SHADOW
1658                     //Now that we have taken a copy we will draw over the existing bitmap so that we can make it as shadow bitmap
1659                     using (Brush shadowDepthBrush = new SolidBrush(Color.FromArgb(220, Color.White)))
1660                         viewPortGraphics.FillRectangle(shadowDepthBrush, new Rectangle(Point.Empty, new Size(memoryBitmap.Size.Width - viewPortData.ShadowDepth.Width - 1, memoryBitmap.Size.Height - viewPortData.ShadowDepth.Height - 1)));
1661 
1662                     //Now make sure that we draw the image from the temporary bitmap with white color set as transparent
1663                     //so that we achive the 3D effect
1664                     //Make sure that we take into consideration the transparency key
1665                     ImageAttributes transparentColorKey = new ImageAttributes();
1666                     transparentColorKey.SetColorKey(viewPortData.TransparentColor, viewPortData.TransparentColor, ColorAdjustType.Default);
1667                     transparentColorKey.SetColorKey(viewPortData.TransparentColor, viewPortData.TransparentColor, ColorAdjustType.Bitmap);
1668                     viewPortGraphics.DrawImage(temporaryBitmap, new Rectangle(-viewPortData.ShadowDepth.Width, -viewPortData.ShadowDepth.Height, memoryBitmap.Width, memoryBitmap.Height), 0, 0, memoryBitmap.Width, memoryBitmap.Height, GraphicsUnit.Pixel, transparentColorKey);
1669 
1670                     //Now dispose the temporary bitmap
1671                     temporaryBitmap.Dispose();
1672                 }
1673             }
1674         }
1675 
OnThemeChange(object sender, EventArgs e)1676         internal void OnThemeChange(object sender, EventArgs e)
1677         {
1678             ShadowDepth = WorkflowTheme.CurrentTheme.AmbientTheme.ShadowDepth;
1679 
1680             using (WorkflowMessageDispatchData dispatchData = new WorkflowMessageDispatchData(this, EventArgs.Empty))
1681             {
1682                 foreach (WorkflowDesignerMessageFilter filter in dispatchData.Filters)
1683                 {
1684                     try
1685                     {
1686                         ((IWorkflowDesignerMessageSink)filter).OnThemeChange();
1687                     }
1688                     catch (Exception ex)
1689                     {
1690                         Debug.WriteLine(ex);
1691                     }
1692                 }
1693             }
1694 
1695             base.PerformLayout();
1696         }
1697 
OnEnsureVisible(object sender, EventArgs e)1698         private void OnEnsureVisible(object sender, EventArgs e)
1699         {
1700             if (this.ensureVisibleEventHandler != null)
1701             {
1702                 Idle -= this.ensureVisibleEventHandler;
1703                 this.ensureVisibleEventHandler = null;
1704             }
1705 
1706             ISelectionService selectionService = (ISelectionService)GetService(typeof(ISelectionService));
1707             if (selectionService != null && selectionService.SelectionCount > 0)
1708             {
1709                 //We do not want to regenerate a layout event in ensure visible
1710                 ArrayList selectedComponents = new ArrayList(selectionService.GetSelectedComponents());
1711                 for (int i = selectedComponents.Count - 1; i >= 0; i--)
1712                 {
1713                     Rectangle rectangleToMakeVisible = Rectangle.Empty;
1714                     if (selectedComponents[i] is Activity)
1715                     {
1716                         ActivityDesigner activityDesigner = ActivityDesigner.GetDesigner(selectedComponents[i] as Activity);
1717                         if (activityDesigner != null)
1718                         {
1719                             rectangleToMakeVisible = activityDesigner.Bounds;
1720                             rectangleToMakeVisible.Inflate(WorkflowTheme.CurrentTheme.AmbientTheme.SelectionSize);
1721                             rectangleToMakeVisible.Inflate(WorkflowTheme.CurrentTheme.AmbientTheme.SelectionSize);
1722                         }
1723                     }
1724                     else if (selectedComponents[i] is HitTestInfo)
1725                     {
1726                         rectangleToMakeVisible = ((HitTestInfo)selectedComponents[i]).Bounds;
1727                     }
1728 
1729                     if (!rectangleToMakeVisible.IsEmpty)
1730                         EnsureVisible(rectangleToMakeVisible);
1731                 }
1732             }
1733         }
1734 
EnsureVisible(Rectangle rect)1735         private void EnsureVisible(Rectangle rect)
1736         {
1737             Rectangle clientRectangle = ClientRectangleToLogical(new Rectangle(Point.Empty, ViewPortSize));
1738 
1739             if (!clientRectangle.Contains(rect.Location) || !clientRectangle.Contains(new Point(rect.Right, rect.Bottom)))
1740             {
1741                 Size scrollDelta = new Size();
1742                 if (!clientRectangle.Contains(new Point(rect.Left, clientRectangle.Top)) || !clientRectangle.Contains(new Point(rect.Right, clientRectangle.Top)))
1743                 {
1744                     if (rect.Width > clientRectangle.Width)
1745                         scrollDelta.Width = (rect.Left + rect.Width / 2) - (clientRectangle.Left + clientRectangle.Width / 2);
1746                     else if (rect.Left < clientRectangle.Left)
1747                         scrollDelta.Width = (rect.Left - clientRectangle.Left);
1748                     else
1749                         scrollDelta.Width = (rect.Right - clientRectangle.Right);
1750                 }
1751 
1752                 if (!clientRectangle.Contains(new Point(clientRectangle.Left, rect.Top)) || !clientRectangle.Contains(new Point(clientRectangle.Left, rect.Bottom)))
1753                 {
1754                     if ((rect.Top < clientRectangle.Top) || (rect.Height > clientRectangle.Height))
1755                         scrollDelta.Height = (rect.Top - clientRectangle.Top);
1756                     else
1757                         scrollDelta.Height = rect.Bottom - clientRectangle.Bottom;
1758                 }
1759 
1760                 scrollDelta = LogicalSizeToClient(scrollDelta);
1761                 Point scrollPosition = ScrollPosition;
1762                 ScrollPosition = new Point(scrollPosition.X + scrollDelta.Width, scrollPosition.Y + scrollDelta.Height);
1763             }
1764         }
1765 
OnScroll(object sender, EventArgs e)1766         private void OnScroll(object sender, EventArgs e)
1767         {
1768             //Lets speedup the scrolling logic
1769             InvalidateClientRectangle(Rectangle.Empty);
1770 
1771             ScrollBar scrollBar = sender as ScrollBar;
1772             if (scrollBar != null)
1773             {
1774                 using (WorkflowMessageDispatchData dispatchData = new WorkflowMessageDispatchData(this, e))
1775                 {
1776                     foreach (WorkflowDesignerMessageFilter filter in dispatchData.Filters)
1777                     {
1778                         try
1779                         {
1780                             ((IWorkflowDesignerMessageSink)filter).OnScroll(scrollBar, scrollBar.Value);
1781                         }
1782                         catch (Exception ex)
1783                         {
1784                             Debug.WriteLine(ex);
1785                         }
1786                     }
1787                 }
1788             }
1789         }
1790 
UpdateScrollRange()1791         private void UpdateScrollRange()
1792         {
1793             if (ViewPortSize.Width < 0 || ViewPortSize.Height < 0)
1794                 return;
1795 
1796             Size currentSize = ViewPortSize;
1797             Size maximumScrollSize = LogicalSizeToClient(this.activeLayout.Extent);
1798             Size largeChangeSize = new Size(Math.Min(maximumScrollSize.Width, currentSize.Width), Math.Min(maximumScrollSize.Height, currentSize.Height));
1799 
1800             if (hScrollBar.Maximum != maximumScrollSize.Width)
1801                 hScrollBar.Maximum = maximumScrollSize.Width;
1802             if (vScrollBar.Maximum != maximumScrollSize.Height)
1803                 vScrollBar.Maximum = maximumScrollSize.Height;
1804 
1805             if (hScrollBar.LargeChange != largeChangeSize.Width)
1806             {
1807                 hScrollBar.SmallChange = largeChangeSize.Width / 15;
1808                 hScrollBar.LargeChange = largeChangeSize.Width + 1;
1809             }
1810             if (vScrollBar.LargeChange != largeChangeSize.Height)
1811             {
1812                 vScrollBar.SmallChange = largeChangeSize.Height / 15;
1813                 vScrollBar.LargeChange = largeChangeSize.Height + 1;
1814             }
1815 
1816             int xMaxScrollPos = maximumScrollSize.Width - hScrollBar.LargeChange;
1817             xMaxScrollPos = (xMaxScrollPos < 0) ? 0 : xMaxScrollPos;
1818             if (hScrollBar.Value > xMaxScrollPos)
1819                 hScrollBar.Value = xMaxScrollPos;
1820 
1821             int yMaxScrollPos = maximumScrollSize.Height - vScrollBar.LargeChange;
1822             yMaxScrollPos = (yMaxScrollPos < 0) ? 0 : yMaxScrollPos;
1823             if (vScrollBar.Value > yMaxScrollPos)
1824                 vScrollBar.Value = yMaxScrollPos;
1825 
1826             RefreshDynamicAction();
1827 
1828             bool hScrollBarVisible = hScrollBar.Visible;
1829             if (Controls.Contains(hScrollBar))
1830                 hScrollBar.Visible = (hScrollBar.Maximum > currentSize.Width);
1831 
1832             bool vScrollBarVisible = vScrollBar.Visible;
1833             if (Controls.Contains(vScrollBar))
1834                 vScrollBar.Visible = (vScrollBar.Maximum > currentSize.Height);
1835 
1836             if (hScrollBarVisible != hScrollBar.Visible || vScrollBar.Visible != vScrollBarVisible)
1837             {
1838                 base.PerformLayout();
1839                 Refresh();
1840             }
1841         }
1842 
CreateDynamicAction()1843         private DynamicAction CreateDynamicAction()
1844         {
1845             DynamicAction fitAllAction = new DynamicAction();
1846             fitAllAction.ButtonSize = DynamicAction.ButtonSizes.Large;
1847             fitAllAction.DockAlignment = DesignerContentAlignment.BottomRight;
1848             fitAllAction.DockMargin = new Size(5, 5);
1849 
1850             ActionButton fitallButton = new ActionButton(new Image[] { DR.GetImage(DR.FitToScreen) as Bitmap });
1851             fitallButton.StateChanged += new EventHandler(OnFitToScreen);
1852             fitAllAction.Buttons.Add(fitallButton);
1853 
1854             return fitAllAction;
1855         }
1856 
RefreshDynamicAction()1857         private void RefreshDynamicAction()
1858         {
1859             DynamicActionMessageFilter dynamicActionFilter = GetService(typeof(DynamicActionMessageFilter)) as DynamicActionMessageFilter;
1860             if (dynamicActionFilter == null || this.fitAllAction == null)
1861                 return;
1862 
1863             if (HScrollBar.Maximum > ViewPortSize.Width || VScrollBar.Maximum > ViewPortSize.Height)
1864             {
1865                 //This means we need to show the zoomin icon
1866                 this.fitAllAction.Buttons[0].Description = DR.GetString(DR.FitToScreenDescription);
1867                 this.fitAllAction.Buttons[0].StateImages = new Bitmap[] { DR.GetImage(DR.FitToScreen) as Bitmap };
1868                 dynamicActionFilter.AddAction(this.fitAllAction);
1869             }
1870             else if (Zoom != 100)
1871             {
1872                 //We need to show zoomout icon
1873                 this.fitAllAction.Buttons[0].Description = DR.GetString(DR.FitToWorkflowDescription);
1874                 this.fitAllAction.Buttons[0].StateImages = new Bitmap[] { DR.GetImage(DR.FitToWorkflow) as Bitmap };
1875                 dynamicActionFilter.AddAction(this.fitAllAction);
1876             }
1877             else
1878             {
1879                 //In neither case we remove the action
1880                 dynamicActionFilter.RemoveAction(this.fitAllAction);
1881                 this.fitAllAction.Buttons[0].State = ActionButton.States.Normal;
1882             }
1883         }
1884 
OnFitToScreen(object sender, EventArgs e)1885         private void OnFitToScreen(object sender, EventArgs e)
1886         {
1887             ActionButton fitallButton = sender as ActionButton;
1888             if (fitallButton == null || fitallButton.State != ActionButton.States.Pressed)
1889                 return;
1890 
1891             if (HScrollBar.Maximum > ViewPortSize.Width || VScrollBar.Maximum > ViewPortSize.Height)
1892                 FitToScreenSize();
1893             else if (Zoom != 100)
1894                 FitToWorkflowSize();
1895         }
1896 
OnTabChange(object sender, TabSelectionChangeEventArgs e)1897         private void OnTabChange(object sender, TabSelectionChangeEventArgs e)
1898         {
1899             if (e.CurrentItem.Identifier == (int)TabButtonIds.MultiPage ||
1900                     e.CurrentItem.Identifier == (int)TabButtonIds.Zoom ||
1901                     e.CurrentItem.Identifier == (int)TabButtonIds.Pan)
1902             {
1903                 Rectangle buttonRect = e.SelectedTabBounds;
1904                 CommandID menuID = null;
1905 
1906                 if (e.CurrentItem.Identifier == (int)TabButtonIds.MultiPage)
1907                     menuID = WorkflowMenuCommands.PageLayoutMenu;
1908                 else if (e.CurrentItem.Identifier == (int)TabButtonIds.Zoom)
1909                     menuID = WorkflowMenuCommands.ZoomMenu;
1910                 else
1911                     menuID = WorkflowMenuCommands.PanMenu;
1912 
1913                 IMenuCommandService menuCommandService = (IMenuCommandService)GetService(typeof(IMenuCommandService));
1914                 if (menuCommandService != null)
1915                     menuCommandService.ShowContextMenu(menuID, buttonRect.Right, buttonRect.Top);
1916             }
1917         }
1918 
EnsureScrollBars(HScrollBar newHorizScrollBar, VScrollBar newVertScrollBar)1919         private void EnsureScrollBars(HScrollBar newHorizScrollBar, VScrollBar newVertScrollBar)
1920         {
1921             try
1922             {
1923                 SuspendLayout();
1924 
1925                 if (this.hScrollBar != newHorizScrollBar)
1926                 {
1927                     if (this.hScrollBar != null)
1928                     {
1929                         this.hScrollBar.ValueChanged -= new EventHandler(OnScroll);
1930                         if (Controls.Contains(this.hScrollBar))
1931                             Controls.Remove(this.hScrollBar);
1932                     }
1933 
1934                     this.hScrollBar = newHorizScrollBar;
1935                     if (this.hScrollBar.Parent == null)
1936                     {
1937                         this.hScrollBar.TabStop = false;
1938                         Controls.Add(this.hScrollBar);
1939                     }
1940                 }
1941 
1942                 if (this.vScrollBar != newVertScrollBar)
1943                 {
1944                     if (this.vScrollBar != null)
1945                     {
1946                         this.vScrollBar.ValueChanged -= new EventHandler(OnScroll);
1947                         if (Controls.Contains(this.vScrollBar))
1948                             Controls.Remove(this.vScrollBar);
1949                     }
1950 
1951                     this.vScrollBar = newVertScrollBar;
1952                     if (this.vScrollBar.Parent == null)
1953                     {
1954                         this.vScrollBar.TabStop = false;
1955                         Controls.Add(this.vScrollBar);
1956                     }
1957                 }
1958 
1959                 this.hScrollBar.ValueChanged += new EventHandler(OnScroll);
1960                 this.vScrollBar.ValueChanged += new EventHandler(OnScroll);
1961             }
1962             finally
1963             {
1964                 ResumeLayout(true);
1965             }
1966         }
1967 
PopulateMessageFilters(bool stockFilters)1968         private void PopulateMessageFilters(bool stockFilters)
1969         {
1970             IList<WorkflowDesignerMessageFilter> filters = (stockFilters) ? this.stockMessageFilters : this.customMessageFilters;
1971             Debug.Assert(filters.Count == 0);
1972 
1973             if (stockFilters)
1974             {
1975                 filters.Add(new GlyphManager());
1976                 filters.Add(new WindowManager());
1977             }
1978             else
1979             {
1980                 Debug.Assert(this.rootDesigner != null);
1981 
1982                 if (Capture)
1983                     Capture = false;
1984 
1985                 IList customFilters = ((IWorkflowRootDesigner)this.rootDesigner).MessageFilters;
1986                 foreach (WorkflowDesignerMessageFilter filter in customFilters)
1987                     filters.Add(filter);
1988             }
1989 
1990             foreach (WorkflowDesignerMessageFilter filter in filters)
1991                 filter.SetParentView(this);
1992         }
1993 
DisposeMessageFilters(bool stockFilters)1994         private void DisposeMessageFilters(bool stockFilters)
1995         {
1996             List<WorkflowDesignerMessageFilter> filters = (stockFilters) ? this.stockMessageFilters : this.customMessageFilters;
1997 
1998             //We dispose all the message filters, this is done by copying because some of the
1999             //message filters might remove other dependent messagefilters
2000             ArrayList clonedFilterList = new ArrayList(filters.ToArray());
2001             foreach (WorkflowDesignerMessageFilter filter in clonedFilterList)
2002                 ((IDisposable)filter).Dispose();
2003             filters.Clear();
2004         }
2005         #endregion
2006 
2007         #region Coordinate Transformation Functions
InvalidateClientRectangle(Rectangle clientRectangle)2008         public void InvalidateClientRectangle(Rectangle clientRectangle)
2009         {
2010             if (this.layoutEventHandler == null)
2011             {
2012                 if (!clientRectangle.IsEmpty)
2013                 {
2014                     //Inflate the invalidated rectangle. When zoom factor is less than 1; there is a loss of precision
2015                     clientRectangle.Inflate(1, 1);
2016                     base.Invalidate(clientRectangle);
2017                 }
2018                 else
2019                 {
2020                     base.Invalidate();
2021                 }
2022             }
2023         }
2024 
InvalidateLogicalRectangle(Rectangle logicalRectangle)2025         public void InvalidateLogicalRectangle(Rectangle logicalRectangle)
2026         {
2027             InvalidateClientRectangle(LogicalRectangleToClient(logicalRectangle));
2028         }
2029 
LogicalPointToScreen(Point logicalPoint)2030         public Point LogicalPointToScreen(Point logicalPoint)
2031         {
2032             return PointToScreen(LogicalPointToClient(logicalPoint));
2033         }
2034 
ScreenPointToLogical(Point screenPoint)2035         public Point ScreenPointToLogical(Point screenPoint)
2036         {
2037             return ClientPointToLogical(PointToClient(screenPoint));
2038         }
2039 
LogicalPointToClient(Point logicalPoint)2040         public Point LogicalPointToClient(Point logicalPoint)
2041         {
2042             return LogicalPointToClient(logicalPoint, true);
2043         }
2044 
ClientPointToLogical(Point clientPoint)2045         public Point ClientPointToLogical(Point clientPoint)
2046         {
2047             return ClientPointToLogical(clientPoint, true);
2048         }
2049 
LogicalSizeToClient(Size logicalSize)2050         public Size LogicalSizeToClient(Size logicalSize)
2051         {
2052             Point[] points = new Point[] { new Point(logicalSize) };
2053 
2054             //Scale the point
2055             Matrix scalingMatrix = new Matrix();
2056             scalingMatrix.Scale(ScaleZoomFactor, ScaleZoomFactor);
2057             scalingMatrix.TransformPoints(points);
2058             return new Size(points[0]);
2059         }
2060 
ClientSizeToLogical(Size clientSize)2061         public Size ClientSizeToLogical(Size clientSize)
2062         {
2063             //Scale the size, size scaling does not require translate
2064             Point[] points = new Point[] { new Point(clientSize) };
2065             Matrix scalingMatrix = new Matrix();
2066             scalingMatrix.Scale(ScaleZoomFactor, ScaleZoomFactor);
2067             scalingMatrix.Invert();
2068             scalingMatrix.TransformPoints(points);
2069             scalingMatrix.Invert();
2070             return new Size(points[0]);
2071         }
2072 
LogicalRectangleToClient(Rectangle rectangle)2073         public Rectangle LogicalRectangleToClient(Rectangle rectangle)
2074         {
2075             Debug.Assert(this.activeLayout != null, "active layout should not be null");
2076             Rectangle clientViewPort = (this.activeLayout != null) ? this.activeLayout.MapOutRectangleFromLayout(rectangle) : rectangle;
2077             //
2078 
2079 
2080             return new Rectangle(LogicalPointToClient(clientViewPort.Location, false), LogicalSizeToClient(clientViewPort.Size));
2081         }
2082 
ClientRectangleToLogical(Rectangle rectangle)2083         public Rectangle ClientRectangleToLogical(Rectangle rectangle)
2084         {
2085             //We translate the client viewport to logical view port.
2086             //To do this we first get the view port rectangle scale it down
2087             //then translate it to area of page we would be viewing
2088             Rectangle scaledLogicalViewPort = new Rectangle(ClientPointToLogical(rectangle.Location, false), ClientSizeToLogical(rectangle.Size));
2089             return this.activeLayout.MapInRectangleToLayout(scaledLogicalViewPort);
2090         }
2091 
IsClientPointInActiveLayout(Point clientPoint)2092         internal bool IsClientPointInActiveLayout(Point clientPoint)
2093         {
2094             Point logicalPoint = ClientPointToLogical(clientPoint, false);
2095             return this.activeLayout.IsCoOrdInLayout(logicalPoint);
2096         }
2097 
2098         /*
2099         * Client scale is when we transform the coordinate based on zoom and translate it based on scrolling position and layout
2100         * Logical scale is when we transform the coordinate and map it to a flat coordinate system which goes from 0,0 to m,n
2101         * We also consider the ActiveLayout to transform the coordinates.
2102         */
LogicalPointToClient(Point point, bool mapToLayout)2103         private Point LogicalPointToClient(Point point, bool mapToLayout)
2104         {
2105             if (mapToLayout)
2106                 point = this.activeLayout.MapOutCoOrdFromLayout(point);
2107 
2108             //Scale the point
2109             Matrix scalingMatrix = new Matrix();
2110             scalingMatrix.Scale(ScaleZoomFactor, ScaleZoomFactor);
2111             Point[] points = new Point[] { point };
2112             scalingMatrix.TransformPoints(points);
2113 
2114             //Translate the point
2115             Matrix translateMatrix = new Matrix();
2116             translateMatrix.Translate(-ScrollPosition.X, -ScrollPosition.Y);
2117             translateMatrix.TransformPoints(points);
2118             return points[0];
2119         }
2120 
ClientPointToLogical(Point point, bool mapToLayout)2121         private Point ClientPointToLogical(Point point, bool mapToLayout)
2122         {
2123             Point[] points = new Point[] { point };
2124 
2125             //Translate the point
2126             Matrix translateMatrix = new Matrix();
2127             translateMatrix.Translate(ScrollPosition.X, ScrollPosition.Y);
2128             translateMatrix.TransformPoints(points);
2129 
2130             //Scale down the point
2131             Matrix scalingMatrix = new Matrix();
2132             scalingMatrix.Scale(ScaleZoomFactor, ScaleZoomFactor);
2133             scalingMatrix.Invert();
2134             scalingMatrix.TransformPoints(points);
2135             scalingMatrix.Invert();
2136             if (!mapToLayout)
2137                 return points[0];
2138             else
2139                 return this.activeLayout.MapInCoOrdToLayout(points[0]);
2140         }
2141         #endregion
2142 
2143         #region IServiceProvider Implemetation
IServiceProvider.GetService(Type serviceType)2144         object IServiceProvider.GetService(Type serviceType)
2145         {
2146             return GetService(serviceType);
2147         }
2148 
GetService(Type serviceType)2149         protected override object GetService(Type serviceType)
2150         {
2151             object retVal = null;
2152 
2153             if (serviceType == typeof(CommandID))
2154                 retVal = new CommandID(new Guid("5f1c3c8d-60f1-4b98-b85b-8679f97e8eac"), 0);
2155             else
2156                 retVal = this.serviceProvider.GetService(serviceType);
2157 
2158             return retVal;
2159         }
2160         #endregion
2161 
2162         #region Class WorkflowMessageDispatchData
2163         private sealed class WorkflowMessageDispatchData : IDisposable
2164         {
2165             private WorkflowView workflowView;
2166             private HitTestInfo messageContext = null;
2167 
WorkflowMessageDispatchData(WorkflowView workflowView, EventArgs e)2168             public WorkflowMessageDispatchData(WorkflowView workflowView, EventArgs e)
2169             {
2170                 this.workflowView = workflowView;
2171 
2172                 if (this.workflowView.RootDesigner != null && this.workflowView.stockMessageFilters.Count > 0)
2173                 {
2174                     Point clientPoint = Point.Empty;
2175                     if (e is MouseEventArgs || e is DragEventArgs)
2176                     {
2177                         if (e is MouseEventArgs)
2178                         {
2179                             clientPoint = new Point(((MouseEventArgs)e).X, ((MouseEventArgs)e).Y);
2180                         }
2181                         else if (e is DragEventArgs)
2182                         {
2183                             clientPoint = this.workflowView.PointToClient(new Point(((DragEventArgs)e).X, ((DragEventArgs)e).Y));
2184                             this.workflowView.UpdateLayout();
2185                         }
2186 
2187                         Point logicalPoint = this.workflowView.ClientPointToLogical(clientPoint);
2188                         HitTestInfo hitTestInfo = this.workflowView.RootDesigner.HitTest(logicalPoint);
2189                         this.messageContext = (hitTestInfo != null) ? hitTestInfo : HitTestInfo.Nowhere;
2190                         this.workflowView.messageHitTestContexts.Push(this.messageContext);
2191                     }
2192                 }
2193             }
2194 
IDisposable.Dispose()2195             void IDisposable.Dispose()
2196             {
2197                 if (this.workflowView != null && this.messageContext != null)
2198                 {
2199                     HitTestInfo hittestInfo = this.workflowView.messageHitTestContexts.Pop();
2200                     if (hittestInfo != this.messageContext)
2201                         Debug.Assert(false, "WorkflowView poped wrong message context");
2202                 }
2203             }
2204 
2205             public ReadOnlyCollection<WorkflowDesignerMessageFilter> Filters
2206             {
2207                 get
2208                 {
2209                     //We recreate a new list everytime as in some of the messages dispatched, we there can
2210                     //be additional filters which might be added
2211                     List<WorkflowDesignerMessageFilter> mergedFilterList = new List<WorkflowDesignerMessageFilter>();
2212                     mergedFilterList.AddRange(this.workflowView.customMessageFilters);
2213                     mergedFilterList.AddRange(this.workflowView.stockMessageFilters);
2214                     return mergedFilterList.AsReadOnly();
2215                 }
2216             }
2217         }
2218         #endregion
2219 
2220         #region IMessageFilter Implementation
IMessageFilter.PreFilterMessage(ref Message m)2221         bool IMessageFilter.PreFilterMessage(ref Message m)
2222         {
2223             bool handled = false;
2224             if (m.Msg == NativeMethods.WM_KEYDOWN || m.Msg == NativeMethods.WM_SYSKEYDOWN ||
2225                 m.Msg == NativeMethods.WM_KEYUP || m.Msg == NativeMethods.WM_SYSKEYUP)
2226             {
2227                 Control control = Control.FromHandle(m.HWnd);
2228                 if (control != null && (control == this || Controls.Contains(control)))
2229                 {
2230                     KeyEventArgs eventArgs = new KeyEventArgs((Keys)(unchecked((int)(long)m.WParam)) | ModifierKeys);
2231                     if (m.Msg == NativeMethods.WM_KEYDOWN || m.Msg == NativeMethods.WM_SYSKEYDOWN)
2232                         OnKeyDown(eventArgs);
2233                     else
2234                         OnKeyUp(eventArgs);
2235 
2236                     handled = eventArgs.Handled;
2237                 }
2238             }
2239 
2240             return handled;
2241         }
2242         #endregion
2243     }
2244 
2245     #region Class WorkflowViewAccessibleObject
2246     [Obsolete("The System.Workflow.* types are deprecated.  Instead, please use the new types from System.Activities.*")]
2247     public class WorkflowViewAccessibleObject : Control.ControlAccessibleObject
2248     {
2249         private WorkflowView workflowView;
2250 
WorkflowViewAccessibleObject(WorkflowView workflowView)2251         public WorkflowViewAccessibleObject(WorkflowView workflowView)
2252             : base(workflowView)
2253         {
2254             if (workflowView == null)
2255                 throw new ArgumentNullException("workflowView");
2256             this.workflowView = workflowView;
2257         }
2258 
2259         public override Rectangle Bounds
2260         {
2261             get
2262             {
2263                 return new Rectangle(this.workflowView.PointToScreen(Point.Empty), this.workflowView.ViewPortSize);
2264             }
2265         }
2266 
2267         public override string DefaultAction
2268         {
2269             get
2270             {
2271                 return DR.GetString(DR.AccessibleAction);
2272             }
2273         }
2274 
2275         public override string Description
2276         {
2277             get
2278             {
2279                 return DR.GetString(DR.WorkflowViewAccessibleDescription);
2280             }
2281         }
2282 
2283         public override string Help
2284         {
2285             get
2286             {
2287                 return DR.GetString(DR.WorkflowViewAccessibleHelp);
2288             }
2289         }
2290 
2291         public override string Name
2292         {
2293             get
2294             {
2295                 return DR.GetString(DR.WorkflowViewAccessibleName);
2296             }
2297 
2298             set
2299             {
2300             }
2301         }
2302 
2303         public override AccessibleRole Role
2304         {
2305             get
2306             {
2307                 return AccessibleRole.Diagram;
2308             }
2309         }
2310 
GetChild(int index)2311         public override AccessibleObject GetChild(int index)
2312         {
2313             return (this.workflowView.RootDesigner != null && index == 0) ? this.workflowView.RootDesigner.AccessibilityObject : base.GetChild(index);
2314         }
2315 
GetChildCount()2316         public override int GetChildCount()
2317         {
2318             return (this.workflowView.RootDesigner != null) ? 1 : -1;
2319         }
2320 
Navigate(AccessibleNavigation navdir)2321         public override AccessibleObject Navigate(AccessibleNavigation navdir)
2322         {
2323             if (navdir == AccessibleNavigation.FirstChild || navdir == AccessibleNavigation.LastChild)
2324                 return GetChild(0);
2325             else
2326                 return base.Navigate(navdir);
2327         }
2328     }
2329     #endregion
2330 
2331     #region WorkflowTimer
2332     internal sealed class WorkflowTimer : IDisposable
2333     {
2334         private static WorkflowTimer workflowTimer;
2335 
2336         private const int TimerInterval = 50;
2337         private Timer timer = null;
2338         private List<ElapsedEventUnit> elapsedEvents = new List<ElapsedEventUnit>();
2339 
2340         internal static WorkflowTimer Default
2341         {
2342             get
2343             {
2344                 if (WorkflowTimer.workflowTimer == null)
2345                     WorkflowTimer.workflowTimer = new WorkflowTimer();
2346                 return WorkflowTimer.workflowTimer;
2347             }
2348         }
2349 
WorkflowTimer()2350         private WorkflowTimer()
2351         {
2352             this.timer = new Timer();
2353             this.timer.Interval = WorkflowTimer.TimerInterval;
2354             this.timer.Tick += new EventHandler(OnTimer);
2355             this.timer.Stop();
2356         }
2357 
~WorkflowTimer()2358         ~WorkflowTimer()
2359         {
2360             Dispose(false);
2361         }
2362 
Dispose()2363         public void Dispose()
2364         {
2365             Dispose(true);
2366             GC.SuppressFinalize(this);
2367         }
2368 
Dispose(bool disposing)2369         private void Dispose(bool disposing)
2370         {
2371             if (this.timer != null)
2372             {
2373                 if (this.timer.Enabled)
2374                     this.timer.Stop();
2375 
2376                 this.timer.Dispose();
2377                 this.timer = null;
2378             }
2379         }
2380 
Subscribe(int elapsedInterval, EventHandler elapsedEventHandler)2381         internal void Subscribe(int elapsedInterval, EventHandler elapsedEventHandler)
2382         {
2383             this.elapsedEvents.Add(new ElapsedEventUnit(elapsedInterval / WorkflowTimer.TimerInterval, elapsedEventHandler));
2384             if (!this.timer.Enabled)
2385                 this.timer.Start();
2386         }
2387 
Unsubscribe(EventHandler elapsedEventHandler)2388         internal void Unsubscribe(EventHandler elapsedEventHandler)
2389         {
2390             List<ElapsedEventUnit> removableElapsedEvents = new List<ElapsedEventUnit>();
2391             foreach (ElapsedEventUnit elapsedEvent in this.elapsedEvents)
2392             {
2393                 if (elapsedEvent.elapsedEventHandler == elapsedEventHandler)
2394                     removableElapsedEvents.Add(elapsedEvent);
2395             }
2396 
2397             foreach (ElapsedEventUnit elapsedEvent in removableElapsedEvents)
2398                 this.elapsedEvents.Remove(elapsedEvent);
2399 
2400             if (this.elapsedEvents.Count == 0 && this.timer.Enabled)
2401                 this.timer.Stop();
2402         }
2403 
OnTimer(object sender, EventArgs e)2404         private void OnTimer(object sender, EventArgs e)
2405         {
2406             List<ElapsedEventUnit> clonedList = new List<ElapsedEventUnit>(this.elapsedEvents);
2407             foreach (ElapsedEventUnit elapsedEvent in clonedList)
2408             {
2409                 elapsedEvent.elapsedTime += 1;
2410                 if (elapsedEvent.elapsedInterval <= elapsedEvent.elapsedTime)
2411                 {
2412                     elapsedEvent.elapsedTime = 0;
2413                     elapsedEvent.elapsedEventHandler(this, EventArgs.Empty);
2414                 }
2415             }
2416         }
2417 
2418         private sealed class ElapsedEventUnit
2419         {
2420             internal EventHandler elapsedEventHandler;
2421             internal int elapsedInterval;
2422             internal int elapsedTime;
2423 
ElapsedEventUnit(int interval, EventHandler eventHandler)2424             internal ElapsedEventUnit(int interval, EventHandler eventHandler)
2425             {
2426                 this.elapsedInterval = interval;
2427                 this.elapsedEventHandler = eventHandler;
2428             }
2429         }
2430     }
2431     #endregion
2432 }
2433