1 namespace System.Workflow.ComponentModel.Design
6 using System.Collections;
7 using System.Collections.Generic;
8 using System.Windows.Forms;
9 using System.ComponentModel;
10 using System.Resources;
11 using System.Diagnostics;
12 using System.Drawing.Design;
13 using System.Drawing.Imaging;
14 using System.Drawing.Printing;
15 using System.Windows.Forms.Design;
16 using System.ComponentModel.Design;
17 using System.ComponentModel.Design.Serialization;
18 using System.Runtime.Serialization.Formatters.Binary;
21 //KEYBOARD: You need to goto <Document and settings\<user name>\ApplicationData\Microsoft\VisualStudio\8.0\" and delete
22 // all of your *.vsk file, becuase VS always picks up keyboard bindings from that file, and also on deveenv.exe /.setup
23 // he does not clean that up.
24 //MENUS: You need to goto <Document and settings\<user name>\ApplicationData\Microsoft\VisualStudio\8.0\1033" and delete
25 // all of your *.prf file, becuase VS always picks up menus from that file, and also on deveenv.exe /.setup
26 // he does not clean that up.
27 internal sealed class CommandSet : IDisposable
29 internal static CommandID[] NavigationToolCommandIds = new CommandID[] { WorkflowMenuCommands.ZoomIn, WorkflowMenuCommands.ZoomOut, WorkflowMenuCommands.Pan, WorkflowMenuCommands.DefaultFilter };
31 private IServiceProvider serviceProvider;
32 private IMenuCommandService menuCommandService;
33 private ISelectionService selectionService;
34 private WorkflowView workflowView;
36 private List<CommandSetItem> commandSet;
37 private CommandSetItem[] zoomCommands;
38 private CommandSetItem[] layoutCommands;
39 private CommandSetItem[] navigationToolCommands;
41 private const string CF_DESIGNER = "CF_WINOEDESIGNERCOMPONENTS";
42 private const string CF_DESIGNERSTATE = "CF_WINOEDESIGNERCOMPONENTSSTATE";
44 private WorkflowDesignerMessageFilter activeFilter;
46 public CommandSet(IServiceProvider serviceProvider)
48 Debug.Assert(serviceProvider != null);
49 this.serviceProvider = serviceProvider;
51 this.menuCommandService = (IMenuCommandService)this.serviceProvider.GetService(typeof(IMenuCommandService));
52 if (this.menuCommandService == null)
53 throw new InvalidOperationException(SR.GetString(SR.General_MissingService, typeof(IMenuCommandService).FullName));
55 this.workflowView = serviceProvider.GetService(typeof(WorkflowView)) as WorkflowView;
56 if (this.workflowView == null)
57 throw new InvalidOperationException(SR.GetString(SR.General_MissingService, typeof(WorkflowView).FullName));
59 this.selectionService = (ISelectionService)this.serviceProvider.GetService(typeof(ISelectionService));
60 if (this.selectionService == null)
61 throw new InvalidOperationException(SR.GetString(SR.General_MissingService, typeof(ISelectionService).FullName));
63 this.commandSet = new List<CommandSetItem>();
64 this.commandSet.AddRange(new CommandSetItem[] {
66 new CommandSetItem(new EventHandler(OnStatusAlways), new EventHandler(OnMenuSaveWorkflowAsImage), WorkflowMenuCommands.SaveAsImage),
67 new CommandSetItem(new EventHandler(OnStatusAlways), new EventHandler(OnMenuCopyToClipboard), WorkflowMenuCommands.CopyToClipboard),
70 new CommandSetItem(new EventHandler(OnStatusPrint), new EventHandler(OnMenuPrint), WorkflowMenuCommands.Print),
71 new CommandSetItem(new EventHandler(OnStatusPageSetup), new EventHandler(OnMenuPageSetup), WorkflowMenuCommands.PageSetup),
74 new CommandSetItem(new EventHandler(OnStatusDelete), new EventHandler(OnMenuDelete), MenuCommands.Delete),
75 new CommandSetItem(new EventHandler(OnStatusCopy), new EventHandler(OnMenuCopy), MenuCommands.Copy),
76 new CommandSetItem(new EventHandler(OnStatusCut), new EventHandler(OnMenuCut), MenuCommands.Cut),
77 new CommandSetItem(new EventHandler(OnStatusPaste), new EventHandler(OnMenuPaste), MenuCommands.Paste, true),
78 new CommandSetItem(new EventHandler(OnStatusAlways), new EventHandler(OnMenuSelectAll), MenuCommands.SelectAll),
81 new CommandSetItem(new EventHandler(OnStatusAlways), new EventHandler(OnMenuDesignerProperties), WorkflowMenuCommands.DesignerProperties),
83 // IMPORTANT: Microsoft does not handle this command, so VS.NET sends it to solution explorer
84 // window, which enables this meu item on the for the current file node
85 new CommandSetItem(new EventHandler(OnStatusAlways), new EventHandler(OnViewCode), new CommandID(StandardCommands.Cut.Guid, 333)),
88 new CommandSetItem(new EventHandler(OnStatusAlways), new EventHandler(OnKeyCancel), MenuCommands.KeyCancel),
89 new CommandSetItem(new EventHandler(OnStatusAlways), new EventHandler(OnKeyCancel), MenuCommands.KeyReverseCancel),
90 new CommandSetItem(new EventHandler(OnStatusAlways), new EventHandler(OnKeyMove), MenuCommands.KeyMoveUp),
91 new CommandSetItem(new EventHandler(OnStatusAlways), new EventHandler(OnKeyMove), MenuCommands.KeyMoveDown),
92 new CommandSetItem(new EventHandler(OnStatusAlways), new EventHandler(OnKeyMove), MenuCommands.KeyMoveLeft),
93 new CommandSetItem(new EventHandler(OnStatusAlways), new EventHandler(OnKeyMove), MenuCommands.KeyMoveRight),
94 new CommandSetItem(new EventHandler(OnStatusAlways), new EventHandler(OnKeyMove), MenuCommands.KeySelectNext),
95 new CommandSetItem(new EventHandler(OnStatusAlways), new EventHandler(OnKeyMove), MenuCommands.KeySelectPrevious),
96 new CommandSetItem(new EventHandler(OnStatusExpandCollapse), new EventHandler(OnExpandCollapse), WorkflowMenuCommands.Expand),
97 new CommandSetItem(new EventHandler(OnStatusExpandCollapse), new EventHandler(OnExpandCollapse), WorkflowMenuCommands.Collapse),
98 new CommandSetItem(new EventHandler(OnStatusEnable), new EventHandler(OnEnable), WorkflowMenuCommands.Disable, true),
99 new CommandSetItem(new EventHandler(OnStatusEnable), new EventHandler(OnEnable), WorkflowMenuCommands.Enable, true),
100 new CommandSetItem(new EventHandler(OnStatusAlways), new EventHandler(OnCreateTheme), WorkflowMenuCommands.CreateTheme),
101 new CommandSetItem(new EventHandler(OnStatusAlways), new EventHandler(OnChangeTheme), WorkflowMenuCommands.ChangeTheme),
102 new CommandSetItem(new EventHandler(OnStatusAnySelection), new EventHandler(OnKeyDefault), MenuCommands.KeyDefaultAction),
103 new CommandSetItem(new EventHandler(OnStatusAlways), new EventHandler(OnKeyPageDnUp), WorkflowMenuCommands.PageUp),
104 new CommandSetItem(new EventHandler(OnStatusAlways), new EventHandler(OnKeyPageDnUp), WorkflowMenuCommands.PageDown),
109 //WorkflowView commands
110 this.zoomCommands = new CommandSetItem[]
112 new CommandSetItem(new EventHandler(OnStatusZoom), new EventHandler(OnZoom), WorkflowMenuCommands.Zoom400Mode, DR.GetString(DR.Zoom400Mode)),
113 new CommandSetItem(new EventHandler(OnStatusZoom), new EventHandler(OnZoom), WorkflowMenuCommands.Zoom300Mode, DR.GetString(DR.Zoom300Mode)),
114 new CommandSetItem(new EventHandler(OnStatusZoom), new EventHandler(OnZoom), WorkflowMenuCommands.Zoom200Mode, DR.GetString(DR.Zoom200Mode)),
115 new CommandSetItem(new EventHandler(OnStatusZoom), new EventHandler(OnZoom), WorkflowMenuCommands.Zoom150Mode, DR.GetString(DR.Zoom150Mode)),
116 new CommandSetItem(new EventHandler(OnStatusZoom), new EventHandler(OnZoom), WorkflowMenuCommands.Zoom100Mode, DR.GetString(DR.Zoom100Mode)),
117 new CommandSetItem(new EventHandler(OnStatusZoom), new EventHandler(OnZoom), WorkflowMenuCommands.Zoom75Mode, DR.GetString(DR.Zoom75Mode)),
118 new CommandSetItem(new EventHandler(OnStatusZoom), new EventHandler(OnZoom), WorkflowMenuCommands.Zoom50Mode, DR.GetString(DR.Zoom50Mode)),
119 new CommandSetItem(new EventHandler(OnStatusZoom), new EventHandler(OnZoom), WorkflowMenuCommands.ShowAll, DR.GetString(DR.ZoomShowAll)),
121 this.commandSet.AddRange(this.zoomCommands);
123 this.layoutCommands = new CommandSetItem[]
125 new CommandSetItem(new EventHandler(OnStatusLayout), new EventHandler(OnPageLayout), WorkflowMenuCommands.DefaultPage),
126 new CommandSetItem(new EventHandler(OnStatusLayout), new EventHandler(OnPageLayout), WorkflowMenuCommands.PrintPreviewPage),
127 new CommandSetItem(new EventHandler(OnStatusLayout), new EventHandler(OnPageLayout), WorkflowMenuCommands.PrintPreview),
129 this.commandSet.AddRange(this.layoutCommands);
131 this.navigationToolCommands = new CommandSetItem[]
133 new CommandSetItem(new EventHandler(OnStatusMessageFilter), new EventHandler(OnMessageFilterChanged), NavigationToolCommandIds[0]),
134 new CommandSetItem(new EventHandler(OnStatusMessageFilter), new EventHandler(OnMessageFilterChanged), NavigationToolCommandIds[1]),
135 new CommandSetItem(new EventHandler(OnStatusMessageFilter), new EventHandler(OnMessageFilterChanged), NavigationToolCommandIds[2]),
136 new CommandSetItem(new EventHandler(OnStatusMessageFilter), new EventHandler(OnMessageFilterChanged), NavigationToolCommandIds[3]),
139 this.commandSet.AddRange(this.navigationToolCommands);
141 // add all menu commands
142 for (int i = 0; i < this.commandSet.Count; i++)
144 if (this.menuCommandService.FindCommand(this.commandSet[i].CommandID) == null)
145 this.menuCommandService.AddCommand(this.commandSet[i]);
148 IComponentChangeService changeService = this.serviceProvider.GetService(typeof(IComponentChangeService)) as IComponentChangeService;
149 if (changeService != null)
150 changeService.ComponentChanged += new ComponentChangedEventHandler(OnComponentChanged);
152 // Now setup the default command GUID for this designer. This GUID is also used in our toolbar
153 // definition file to identify toolbars we own. We store the GUID in a command ID here in the
154 // dictionary of the root component. Our host may pull this GUID out and use it.
155 IDictionaryService ds = this.serviceProvider.GetService(typeof(IDictionaryService)) as IDictionaryService;
157 ds.SetValue(typeof(CommandID), new CommandID(new Guid("5f1c3c8d-60f1-4b98-b85b-8679f97e8eac"), 0));
160 #region IDisposable Members
161 public void Dispose()
163 IComponentChangeService changeService = this.serviceProvider.GetService(typeof(IComponentChangeService)) as IComponentChangeService;
164 if (changeService != null)
165 changeService.ComponentChanged -= new ComponentChangedEventHandler(OnComponentChanged);
167 if (this.activeFilter != null)
169 this.workflowView.RemoveDesignerMessageFilter(this.activeFilter);
170 this.activeFilter.Dispose();
171 this.activeFilter = null;
174 this.selectionService = null;
176 for (int i = 0; i < this.commandSet.Count; i++)
177 this.menuCommandService.RemoveCommand(this.commandSet[i]);
178 this.menuCommandService = null;
182 #region Helper fucntions
183 internal void UpdateCommandSet()
185 // whip through all of the commands and ask them to update.
186 for (int i = 0; i < this.commandSet.Count; i++)
187 this.commandSet[i].UpdateStatus();
190 internal void UpdateZoomCommands(bool enable)
192 int commandID = this.ConvertToZoomCommand(this.workflowView.Zoom);
193 foreach (MenuCommand menuCommand in this.zoomCommands)
195 menuCommand.Enabled = enable;
196 menuCommand.Checked = (commandID == menuCommand.CommandID.ID);
200 internal void UpdatePageLayoutCommands(bool enable)
202 //we might have two commands checked at the same (PrintPreviewPage and PrintPreview - since they have sligtly different logic (one is toggle and the other is not))
203 foreach (MenuCommand menuCommand in this.layoutCommands)
205 menuCommand.Enabled = enable;
206 menuCommand.Checked = this.workflowView.PrintPreviewMode ? (menuCommand.CommandID == WorkflowMenuCommands.PrintPreview || menuCommand.CommandID == WorkflowMenuCommands.PrintPreviewPage) : menuCommand.CommandID == WorkflowMenuCommands.DefaultPage;
210 internal void UpdatePanCommands(bool enable)
212 CommandID commandID = ConvertMessageFilterToCommandID();
213 foreach (MenuCommand menuCommand in this.navigationToolCommands)
215 menuCommand.Enabled = enable;
216 menuCommand.Checked = (commandID == menuCommand.CommandID);
220 private CommandID ConvertMessageFilterToCommandID()
222 if (this.activeFilter is PanningMessageFilter)
224 return WorkflowMenuCommands.Pan;
226 else if (this.activeFilter is ZoomingMessageFilter)
228 if (((ZoomingMessageFilter)this.activeFilter).ZoomingIn)
229 return WorkflowMenuCommands.ZoomIn;
231 return WorkflowMenuCommands.ZoomOut;
235 return WorkflowMenuCommands.DefaultFilter;
239 private int ConvertToZoomLevel(int commandId)
242 if (commandId == WorkflowMenuCommands.Zoom400Mode.ID) zoomLevel = 400;
243 else if (commandId == WorkflowMenuCommands.Zoom300Mode.ID) zoomLevel = 300;
244 else if (commandId == WorkflowMenuCommands.Zoom200Mode.ID) zoomLevel = 200;
245 else if (commandId == WorkflowMenuCommands.Zoom150Mode.ID) zoomLevel = 150;
246 else if (commandId == WorkflowMenuCommands.Zoom100Mode.ID) zoomLevel = 100;
247 else if (commandId == WorkflowMenuCommands.Zoom75Mode.ID) zoomLevel = 75;
248 else if (commandId == WorkflowMenuCommands.Zoom50Mode.ID) zoomLevel = 50;
253 private int ConvertToZoomCommand(int zoomLevel)
255 int commandID = 0; //do not select anything if the zoom level is not one of the standard ones
256 if (zoomLevel == 400) commandID = WorkflowMenuCommands.Zoom400Mode.ID;
257 else if (zoomLevel == 300) commandID = WorkflowMenuCommands.Zoom300Mode.ID;
258 else if (zoomLevel == 200) commandID = WorkflowMenuCommands.Zoom200Mode.ID;
259 else if (zoomLevel == 150) commandID = WorkflowMenuCommands.Zoom150Mode.ID;
260 else if (zoomLevel == 100) commandID = WorkflowMenuCommands.Zoom100Mode.ID;
261 else if (zoomLevel == 75) commandID = WorkflowMenuCommands.Zoom75Mode.ID;
262 else if (zoomLevel == 50) commandID = WorkflowMenuCommands.Zoom50Mode.ID;
268 #region Status Handlers
269 private void OnComponentChanged(object sender, ComponentChangedEventArgs e)
271 if (this.activeFilter != null)
273 this.workflowView.RemoveDesignerMessageFilter(this.activeFilter);
274 this.activeFilter = null;
275 UpdatePanCommands(true);
279 private void OnStatusZoom(object sender, EventArgs e)
281 UpdateZoomCommands(true);
284 private void OnZoom(object sender, EventArgs e)
286 MenuCommand menuCommand = (MenuCommand)sender;
287 if (menuCommand.CommandID.ID == WorkflowMenuCommands.ShowAll.ID)
289 int newZoom = (int)(100.0f / this.workflowView.ActiveLayout.Scaling * Math.Min((float)this.workflowView.ViewPortSize.Width / (float)this.workflowView.ActiveLayout.Extent.Width, (float)this.workflowView.ViewPortSize.Height / (float)this.workflowView.ActiveLayout.Extent.Height));
290 this.workflowView.Zoom = Math.Min(Math.Max(newZoom, AmbientTheme.MinZoom), AmbientTheme.MaxZoom);
294 this.workflowView.Zoom = ConvertToZoomLevel(menuCommand.CommandID.ID);
297 UpdateZoomCommands(true);
300 private void OnStatusLayout(object sender, EventArgs e)
302 UpdatePageLayoutCommands(true);
305 private void OnPageLayout(object sender, EventArgs e)
307 MenuCommand menuCommand = (MenuCommand)sender;
308 this.workflowView.PrintPreviewMode = (menuCommand.CommandID == WorkflowMenuCommands.PrintPreview) ? !this.workflowView.PrintPreviewMode : (menuCommand.CommandID == WorkflowMenuCommands.PrintPreviewPage);
309 UpdatePageLayoutCommands(true);
312 private void OnStatusMessageFilter(object sender, EventArgs e)
314 UpdatePanCommands(true);
317 private void OnMessageFilterChanged(object sender, EventArgs e)
319 if (this.activeFilter != null)
321 this.workflowView.RemoveDesignerMessageFilter(this.activeFilter);
322 this.activeFilter = null;
325 MenuCommand menuCommand = (MenuCommand)sender;
326 int commandId = menuCommand.CommandID.ID;
327 if (WorkflowMenuCommands.ZoomIn.ID == commandId)
328 this.activeFilter = new ZoomingMessageFilter(true);
329 else if (WorkflowMenuCommands.ZoomOut.ID == commandId)
330 this.activeFilter = new ZoomingMessageFilter(false);
331 else if (WorkflowMenuCommands.Pan.ID == commandId)
332 this.activeFilter = new PanningMessageFilter();
334 if (this.activeFilter != null)
335 this.workflowView.AddDesignerMessageFilter(this.activeFilter);
337 this.workflowView.Focus();
338 UpdatePanCommands(true);
341 private void OnStatusPrint(object sender, EventArgs e)
343 OnStatusAlways(sender, e);
346 private void OnStatusPageSetup(object sender, EventArgs e)
348 OnStatusAlways(sender, e);
351 private void OnStatusCopy(object sender, EventArgs e)
353 MenuCommand cmd = (MenuCommand)sender;
356 IDesignerHost designerHost = this.serviceProvider.GetService(typeof(IDesignerHost)) as IDesignerHost;
357 if (designerHost != null && !designerHost.Loading)
359 ArrayList selectedComponents = new ArrayList(this.selectionService.GetSelectedComponents());
360 enable = Helpers.AreAllActivities(selectedComponents);
364 foreach (Activity activity in selectedComponents)
366 if (activity.Site != null)
368 designerHost = activity.Site.GetService(typeof(IDesignerHost)) as IDesignerHost;
369 if (designerHost != null && this.selectionService.GetComponentSelected(designerHost.RootComponent))
379 cmd.Enabled = enable;
382 private void OnStatusCut(object sender, EventArgs e)
384 OnStatusDelete(sender, e);
387 private void OnStatusDelete(object sender, EventArgs e)
389 MenuCommand cmd = (MenuCommand)sender;
392 // check if we are cutting root component
393 IDesignerHost designerHost = this.serviceProvider.GetService(typeof(IDesignerHost)) as IDesignerHost;
394 if (designerHost != null && designerHost.RootComponent != null && this.selectionService.GetComponentSelected(designerHost.RootComponent))
397 //Check that we are cutting all activities
398 //Check if we are in writable context
399 ICollection components = this.selectionService.GetSelectedComponents();
400 if (!DesignerHelpers.AreComponentsRemovable(components))
403 // check if we can delete these
404 Activity[] topLevelActivities = Helpers.GetTopLevelActivities(components);
405 IDictionary commonParentActivities = Helpers.PairUpCommonParentActivities(topLevelActivities);
406 foreach (DictionaryEntry entry in commonParentActivities)
408 CompositeActivityDesigner compositeActivityDesigner = ActivityDesigner.GetDesigner(entry.Key as Activity) as CompositeActivityDesigner;
409 if (compositeActivityDesigner != null && !compositeActivityDesigner.CanRemoveActivities(new List<Activity>((Activity[])((ArrayList)entry.Value).ToArray(typeof(Activity))).AsReadOnly()))
419 private void OnStatusPaste(object sender, EventArgs e)
421 MenuCommand cmd = (MenuCommand)sender;
424 //Check if we are in writtable context
425 object selectedObject = this.selectionService.PrimarySelection;
426 CompositeActivityDesigner compositeDesigner = ActivityDesigner.GetDesigner(selectedObject as Activity) as CompositeActivityDesigner;
427 if (compositeDesigner == null)
428 compositeDesigner = ActivityDesigner.GetParentDesigner(selectedObject);
430 if (compositeDesigner == null || !compositeDesigner.IsEditable)
433 //Check if data object format is valid
434 IDesignerHost designerHost = this.serviceProvider.GetService(typeof(IDesignerHost)) as IDesignerHost;
435 IToolboxService ts = (IToolboxService)this.serviceProvider.GetService(typeof(IToolboxService));
436 IDataObject dataObj = Clipboard.GetDataObject();
437 if (dataObj == null || designerHost == null || (!dataObj.GetDataPresent(CF_DESIGNER) && (ts != null && !ts.IsSupported(dataObj, designerHost))))
440 //Get the drop target and check if it is valid
441 HitTestInfo hitInfo = null;
442 if (selectedObject is HitTestInfo)
444 hitInfo = (HitTestInfo)selectedObject;
446 else if (selectedObject is CompositeActivity)
448 hitInfo = new HitTestInfo(compositeDesigner, HitTestLocations.Designer);
450 else if (selectedObject is Activity)
452 Activity selectedActivity = selectedObject as Activity;
453 CompositeActivity parentActivity = selectedActivity.Parent;
454 CompositeActivityDesigner parentDesigner = ActivityDesigner.GetDesigner(parentActivity) as CompositeActivityDesigner;
455 if (parentDesigner != null)
456 hitInfo = new ConnectorHitTestInfo(parentDesigner, HitTestLocations.Designer, parentActivity.Activities.IndexOf(selectedActivity) + 1);
459 //Deserialize activities
460 ICollection components = null;
463 components = CompositeActivityDesigner.DeserializeActivitiesFromDataObject(this.serviceProvider, dataObj);
465 catch (CheckoutException ex)
467 if (ex != CheckoutException.Canceled)
471 cmd.Enabled = (components != null && hitInfo != null && compositeDesigner.CanInsertActivities(hitInfo, new List<Activity>(Helpers.GetTopLevelActivities(components)).AsReadOnly()));
474 private void OnStatusAnySelection(object sender, EventArgs e)
476 // any selection means that except the root component, if any of the activity is
477 // selected then enable it
478 MenuCommand cmd = (MenuCommand)sender;
479 IDesignerHost designerHost = this.serviceProvider.GetService(typeof(IDesignerHost)) as IDesignerHost;
480 cmd.Enabled = (designerHost != null && this.selectionService.GetSelectedComponents().Count > 0 &&
481 !this.selectionService.GetComponentSelected(designerHost.RootComponent));
484 private void OnStatusAlways(object sender, EventArgs e)
486 MenuCommand cmd = (MenuCommand)sender;
490 private void OnStatusExpandCollapse(object sender, EventArgs e)
492 MenuCommand menuCommand = (MenuCommand)sender;
494 int expandCollapseItems = 0;
495 foreach (object obj in this.selectionService.GetSelectedComponents())
497 Activity activity = obj as Activity;
498 if (activity != null)
500 CompositeActivityDesigner compositeDesigner = ActivityDesigner.GetDesigner(activity) as CompositeActivityDesigner;
501 if (compositeDesigner != null && compositeDesigner.CanExpandCollapse &&
502 ((menuCommand.CommandID == WorkflowMenuCommands.Expand && !compositeDesigner.Expanded) ||
503 (menuCommand.CommandID == WorkflowMenuCommands.Collapse && compositeDesigner.Expanded)))
505 expandCollapseItems += 1;
510 menuCommand.Visible = menuCommand.Enabled = (expandCollapseItems == this.selectionService.SelectionCount);
513 private void OnStatusEnable(object sender, EventArgs e)
515 MenuCommand menuCommand = (MenuCommand)sender;
517 bool enabledPropertyValue = true;
519 ArrayList selectedObjects = new ArrayList(this.selectionService.GetSelectedComponents());
520 for (int i = 0; i < selectedObjects.Count && enabled; i++)
522 Activity activity = selectedObjects[i] as Activity;
523 if (activity != null)
525 ActivityDesigner activityDesigner = ActivityDesigner.GetDesigner(activity);
526 if (activityDesigner == null || activityDesigner.IsLocked ||
527 (i > 0 && enabledPropertyValue != activity.Enabled) ||
528 (this.workflowView.RootDesigner != null && this.workflowView.RootDesigner.Activity == activity))
534 enabledPropertyValue = activity.Enabled;
543 menuCommand.Visible = menuCommand.Enabled = (enabled && ((menuCommand.CommandID == WorkflowMenuCommands.Enable && !enabledPropertyValue) || (menuCommand.CommandID == WorkflowMenuCommands.Disable && enabledPropertyValue)));
548 #region Execute Handlers
549 private void OnKeyDefault(object sender, EventArgs e)
551 SendKeyDownCommand(Keys.Enter);
554 //sends specified key to the wf view, returns the .Handled flag
555 private bool SendKeyDownCommand(Keys key)
557 IDesignerHost host = this.serviceProvider.GetService(typeof(IDesignerHost)) as IDesignerHost;
560 IRootDesigner rootDesigner = ActivityDesigner.GetDesigner(host.RootComponent as Activity) as IRootDesigner;
561 if (rootDesigner != null)
563 WorkflowView view = rootDesigner.GetView(ViewTechnology.Default) as WorkflowView;
566 //because the some key presses are not coming into the Microsoft OnKeyDown
567 //we need to do this work around to manually send the keypress into the designer
569 KeyEventArgs eventArgs = new KeyEventArgs(key);
570 view.OnCommandKey(eventArgs);
571 return eventArgs.Handled;
579 private void OnKeyMove(object sender, EventArgs e)
581 object selectedObject = this.selectionService.PrimarySelection;
582 if (selectedObject == null)
585 MenuCommand menuCommand = (MenuCommand)sender;
587 Keys key = Keys.Left;
589 if (menuCommand.CommandID.ID == MenuCommands.KeyMoveDown.ID)
591 else if (menuCommand.CommandID.ID == MenuCommands.KeyMoveUp.ID)
593 else if (menuCommand.CommandID.ID == MenuCommands.KeyMoveLeft.ID)
595 else if (menuCommand.CommandID.ID == MenuCommands.KeyMoveRight.ID)
597 else if (menuCommand.CommandID.ID == MenuCommands.KeySelectNext.ID)
599 else if (menuCommand.CommandID.ID == MenuCommands.KeySelectPrevious.ID)
600 { key = Keys.Tab | Keys.Shift; }
602 SendKeyDownCommand(key);
605 private void OnExpandCollapse(object sender, EventArgs e)
607 // on enter key we want to do DoDefault of the designer
608 MenuCommand menuCommand = (MenuCommand)sender;
610 foreach (object obj in this.selectionService.GetSelectedComponents())
612 Activity activity = obj as Activity;
613 if (activity != null)
615 CompositeActivityDesigner designer = ActivityDesigner.GetDesigner(activity) as CompositeActivityDesigner;
616 if (designer != null)
617 designer.Expanded = (menuCommand.CommandID.ID == WorkflowMenuCommands.Expand.ID);
621 MenuCommand expandCommand = this.menuCommandService.FindCommand(WorkflowMenuCommands.Expand);
622 if (expandCommand != null)
623 OnStatusExpandCollapse(expandCommand, EventArgs.Empty);
625 MenuCommand collapseCommand = this.menuCommandService.FindCommand(WorkflowMenuCommands.Collapse);
626 if (collapseCommand != null)
627 OnStatusExpandCollapse(collapseCommand, EventArgs.Empty);
630 private void OnEnable(object sender, EventArgs e)
632 // on enter key we want to do DoDefault of the designer
633 MenuCommand menuCommand = (MenuCommand)sender;
635 DesignerTransaction trans = null;
636 IComponent selectedComponent = this.selectionService.PrimarySelection as IComponent;
637 if (selectedComponent != null && selectedComponent.Site != null)
639 IDesignerHost host = selectedComponent.Site.GetService(typeof(IDesignerHost)) as IDesignerHost;
641 trans = host.CreateTransaction(SR.GetString(SR.ChangingEnabled));
646 foreach (object obj in this.selectionService.GetSelectedComponents())
648 Activity activity = obj as Activity;
649 if (activity != null)
651 ActivityDesigner activityDesigner = ActivityDesigner.GetDesigner(activity);
652 if (activityDesigner != null && !activityDesigner.IsLocked)
654 PropertyDescriptor propertyDescriptor = TypeDescriptor.GetProperties(activity)["Enabled"];
655 if (propertyDescriptor != null)
656 propertyDescriptor.SetValue(activity, !activity.Enabled);
667 ((IDisposable)trans).Dispose();
670 MenuCommand commentCommand = this.menuCommandService.FindCommand(WorkflowMenuCommands.Disable);
671 if (commentCommand != null)
672 OnStatusEnable(commentCommand, EventArgs.Empty);
674 MenuCommand uncommentCommand = this.menuCommandService.FindCommand(WorkflowMenuCommands.Enable);
675 if (uncommentCommand != null)
676 OnStatusEnable(uncommentCommand, EventArgs.Empty);
679 private void OnCreateTheme(object sender, EventArgs e)
681 ThemeConfigurationDialog themeConfigDialog = new ThemeConfigurationDialog(this.serviceProvider);
682 if (themeConfigDialog.ShowDialog() == DialogResult.OK)
684 WorkflowTheme themeToApply = themeConfigDialog.ComposedTheme.Clone() as WorkflowTheme;
685 if (themeToApply != null)
687 WorkflowTheme.CurrentTheme = themeToApply;
688 WorkflowTheme.SaveThemeSettingToRegistry();
693 private void OnChangeTheme(object sender, EventArgs e)
695 IExtendedUIService extUIService = this.serviceProvider.GetService(typeof(IExtendedUIService)) as IExtendedUIService;
696 if (extUIService != null)
697 extUIService.ShowToolsOptions();
700 private void OnKeyCancel(object sender, EventArgs e)
702 SendKeyDownCommand(Keys.Escape);
705 private void OnKeyPageDnUp(object sender, EventArgs e)
707 MenuCommand menuCommand = (MenuCommand)sender;
708 SendKeyDownCommand((menuCommand.CommandID == WorkflowMenuCommands.PageUp) ? Keys.PageUp : Keys.PageDown);
711 private void OnViewCode(object sender, EventArgs e)
713 IDesignerHost designerHost = this.serviceProvider.GetService(typeof(IDesignerHost)) as IDesignerHost;
714 IComponent rootComponent = (designerHost != null) ? designerHost.RootComponent : null;
715 if (rootComponent != null)
717 IMemberCreationService memberCreationService = rootComponent.Site.GetService(typeof(IMemberCreationService)) as IMemberCreationService;
718 if (memberCreationService != null)
719 memberCreationService.ShowCode();
723 private void OnMenuPageSetup(object sender, EventArgs e)
725 PrinterSettings.StringCollection printers = PrinterSettings.InstalledPrinters;
726 if (printers.Count < 1)
728 DesignerHelpers.ShowError(this.serviceProvider, DR.GetString(DR.ThereIsNoPrinterInstalledErrorMessage));
732 WorkflowPageSetupDialog pageSetupDialog = new WorkflowPageSetupDialog(this.serviceProvider);
733 if (DialogResult.OK == pageSetupDialog.ShowDialog())
734 this.workflowView.PerformLayout(false);
737 private void OnMenuSaveWorkflowAsImage(object sender, EventArgs e)
739 List<SupportedImageFormats> supportedFormats = new List<SupportedImageFormats>();
740 supportedFormats.Add(new SupportedImageFormats(DR.GetString(DR.BMPImageFormat), ImageFormat.Bmp));
741 supportedFormats.Add(new SupportedImageFormats(DR.GetString(DR.JPEGImageFormat), ImageFormat.Jpeg));
742 supportedFormats.Add(new SupportedImageFormats(DR.GetString(DR.PNGImageFormat), ImageFormat.Png));
743 supportedFormats.Add(new SupportedImageFormats(DR.GetString(DR.TIFFImageFormat), ImageFormat.Tiff));
744 supportedFormats.Add(new SupportedImageFormats(DR.GetString(DR.WMFImageFormat), ImageFormat.Wmf));
745 supportedFormats.Add(new SupportedImageFormats(DR.GetString(DR.EXIFImageFormat), ImageFormat.Exif));
746 supportedFormats.Add(new SupportedImageFormats(DR.GetString(DR.EMFImageFormat), ImageFormat.Emf));
748 SaveFileDialog saveFileDialog = new SaveFileDialog();
749 saveFileDialog.Title = DR.GetString(DR.SaveWorkflowImageDialogTitle);
750 saveFileDialog.DefaultExt = "bmp";
752 string filter = String.Empty;
753 foreach (SupportedImageFormats format in supportedFormats)
754 filter += (filter.Length > 0) ? "|" + format.Description : format.Description;
756 saveFileDialog.Filter = filter;
757 saveFileDialog.FilterIndex = 0;
758 if (saveFileDialog.ShowDialog() == DialogResult.OK && saveFileDialog.FilterIndex > 0 && saveFileDialog.FilterIndex <= supportedFormats.Count)
759 this.workflowView.SaveWorkflowImage(saveFileDialog.FileName, supportedFormats[saveFileDialog.FilterIndex - 1].Format);
762 private void OnMenuCopyToClipboard(object sender, EventArgs e)
764 this.workflowView.SaveWorkflowImageToClipboard();
767 private void OnMenuPrint(object sender, EventArgs e)
769 //check if the printers are installed
770 PrinterSettings.StringCollection printers = PrinterSettings.InstalledPrinters;
771 if (printers.Count < 1)
773 DesignerHelpers.ShowError(this.serviceProvider, DR.GetString(DR.ThereIsNoPrinterInstalledErrorMessage));
777 //check printer selection before actually printing
778 PrintDocument printDoc = this.workflowView.PrintDocument;
779 PrintDialog printDialog = new System.Windows.Forms.PrintDialog();
780 printDialog.AllowPrintToFile = false;
781 printDialog.Document = printDoc;
785 if (DialogResult.OK == printDialog.ShowDialog())
787 //cache main settings
788 PrinterSettings cachedPrinterSettings = printDoc.PrinterSettings;
789 PageSettings cachedPageSettings = printDoc.DefaultPageSettings;
791 //set the user selected settings
792 //The printer dialog itself calls print on print document we do not have to call it.
793 printDoc.PrinterSettings = printDialog.PrinterSettings;
794 printDoc.DefaultPageSettings = printDialog.Document.DefaultPageSettings;
799 //and restore the main settings back
800 printDoc.PrinterSettings = cachedPrinterSettings;
801 printDoc.DefaultPageSettings = cachedPageSettings;
805 //todo: copy updated settings from the dialog to the print doc
806 //in the worst case it's a no-op, in case user clicked apply/cancel it's the only way to
807 //update the settings (see Winoe#3129 and VSWhidbey#403124 for more details)
810 catch (Exception exception)
812 string errorString = DR.GetString(DR.SelectedPrinterIsInvalidErrorMessage);
813 errorString += "\n" + exception.Message;
814 DesignerHelpers.ShowError(this.serviceProvider, errorString);
818 private void OnMenuDesignerProperties(object sender, EventArgs e)
820 if (this.menuCommandService != null)
821 this.menuCommandService.GlobalInvoke(MenuCommands.PropertiesWindow);
824 private void OnMenuCut(object sender, EventArgs e)
826 //check if we are cutting root component
827 IDesignerHost designerHost = this.serviceProvider.GetService(typeof(IDesignerHost)) as IDesignerHost;
828 if (designerHost != null && this.selectionService.GetComponentSelected(designerHost.RootComponent))
831 //Check that we are cutting all activities
832 //Check if we are in writable context
833 ICollection components = this.selectionService.GetSelectedComponents();
834 if (!Helpers.AreAllActivities(components) || !DesignerHelpers.AreAssociatedDesignersMovable(components))
837 // copy the selected component to clipboard
838 OnMenuCopy(sender, e);
840 // Set transaction description string based on number of activities being moved
841 string description = String.Empty;
843 if (components.Count > 1)
845 description = SR.GetString(SR.CutMultipleActivities, components.Count);
849 ArrayList componentList = new ArrayList(components);
850 if (componentList.Count > 0)
851 description = SR.GetString(SR.CutSingleActivity, (componentList[0] as Activity).Name);
853 description = SR.GetString(SR.CutActivity);
856 DesignerTransaction cutTransaction = designerHost.CreateTransaction(description);
860 OnMenuDelete(sender, e);
861 cutTransaction.Commit();
865 cutTransaction.Cancel();
869 private void OnMenuCopy(object sender, EventArgs e)
871 //Make sure that we are copying activities
872 if (!Helpers.AreAllActivities(this.selectionService.GetSelectedComponents()))
875 // serialize all top level activities to the store
876 Activity[] topLevelActivities = Helpers.GetTopLevelActivities(this.selectionService.GetSelectedComponents());
877 IDataObject dataObject = CompositeActivityDesigner.SerializeActivitiesToDataObject(this.serviceProvider, topLevelActivities);
878 Clipboard.SetDataObject(dataObject);
881 private void OnMenuPaste(object sender, EventArgs e)
883 object selectedObject = this.selectionService.PrimarySelection;
884 CompositeActivityDesigner compositeDesigner = ActivityDesigner.GetDesigner(selectedObject as Activity) as CompositeActivityDesigner;
885 if (compositeDesigner == null)
886 compositeDesigner = ActivityDesigner.GetParentDesigner(selectedObject);
888 if (compositeDesigner == null || !compositeDesigner.IsEditable)
891 // deserialize activities
892 IDataObject dataObj = Clipboard.GetDataObject();
893 ICollection components = null;
897 components = CompositeActivityDesigner.DeserializeActivitiesFromDataObject(this.serviceProvider, dataObj, true);
901 if (ex != CheckoutException.Canceled)
902 throw new Exception(DR.GetString(DR.ActivityInsertError) + "\n" + ex.Message, ex);
905 if (components == null)
906 throw new InvalidOperationException(DR.GetString(DR.InvalidOperationBadClipboardFormat));
908 // get the drop target
909 HitTestInfo hitInfo = null;
910 if (selectedObject is HitTestInfo)
912 hitInfo = (HitTestInfo)selectedObject;
914 else if (selectedObject is CompositeActivity)
916 hitInfo = new HitTestInfo(compositeDesigner, HitTestLocations.Designer);
918 else if (selectedObject is Activity)
920 Activity selectedActivity = selectedObject as Activity;
921 CompositeActivity parentActivity = selectedActivity.Parent;
922 CompositeActivityDesigner parentDesigner = ActivityDesigner.GetDesigner(parentActivity) as CompositeActivityDesigner;
923 if (parentDesigner != null)
924 hitInfo = new ConnectorHitTestInfo(parentDesigner, HitTestLocations.Designer, parentActivity.Activities.IndexOf(selectedActivity) + 1);
927 List<Activity> topLevelActivities = new List<Activity>(Helpers.GetTopLevelActivities(components));
929 // check if we can insert or not
930 // I know I should have disabled the paste menu it-self, but doing status check for paste gives a big performance hit. I am working on it.
931 if (hitInfo == null || !compositeDesigner.CanInsertActivities(hitInfo, topLevelActivities.AsReadOnly()))
932 throw new Exception(SR.GetString(SR.Error_NoPasteSupport));
934 // Make sure the project has references to all inserted activities (in the case
935 // where an activity is copied from another project
936 IExtendedUIService extendedUIService = this.serviceProvider.GetService(typeof(IExtendedUIService)) as IExtendedUIService;
937 if (extendedUIService != null)
939 foreach (Activity pastedActivity in components)
940 extendedUIService.AddAssemblyReference(pastedActivity.GetType().Assembly.GetName());
943 CompositeActivityDesigner.InsertActivities(compositeDesigner, hitInfo, topLevelActivities.AsReadOnly(), SR.GetString(SR.PastingActivities));
944 Stream componentStateStream = dataObj.GetData(CF_DESIGNERSTATE) as Stream;
945 if (componentStateStream != null)
946 Helpers.DeserializeDesignersFromStream(components, componentStateStream);
948 // set something on selections service
949 this.selectionService.SetSelectedComponents(topLevelActivities.ToArray(), SelectionTypes.Replace);
950 this.workflowView.EnsureVisible(this.selectionService.PrimarySelection);
953 private void OnMenuSelectAll(object sender, EventArgs e)
955 ActivityDesigner rootDesigner = ActivityDesigner.GetSafeRootDesigner(this.serviceProvider) as ActivityDesigner;
956 if (rootDesigner != null)
958 List<Activity> activities = new List<Activity>();
959 if (rootDesigner.Activity is CompositeActivity)
960 activities.AddRange(Helpers.GetNestedActivities(rootDesigner.Activity as CompositeActivity));
961 this.selectionService.SetSelectedComponents(activities.ToArray(), SelectionTypes.Replace);
965 private void OnMenuDelete(object sender, EventArgs e)
967 SendKeyDownCommand(Keys.Delete);
972 #region Class SupportedImageFormats
973 internal class SupportedImageFormats
975 public string Description;
976 public ImageFormat Format;
978 public SupportedImageFormats(string description, ImageFormat imageFormat)
980 Description = description;
981 Format = imageFormat;
986 #region Class CommandSetItem
987 internal sealed class CommandSetItem : MenuCommand
989 private EventHandler statusHandler;
990 private bool immidiateStatusUpdate = false;
992 public CommandSetItem(EventHandler statusHandler, EventHandler invokeHandler, CommandID id)
993 : base(invokeHandler, id)
995 this.statusHandler = statusHandler;
998 public CommandSetItem(EventHandler statusHandler, EventHandler invokeHandler, CommandID id, string text)
999 : this(statusHandler, invokeHandler, id)
1001 Properties["Text"] = text;
1004 public CommandSetItem(EventHandler statusHandler, EventHandler invokeHandler, CommandID id, bool immidiateStatusUpdate)
1005 : this(statusHandler, invokeHandler, id)
1007 this.immidiateStatusUpdate = immidiateStatusUpdate;
1010 public override int OleStatus
1014 if (this.immidiateStatusUpdate)
1016 return base.OleStatus;
1020 public void UpdateStatus()
1022 if (statusHandler != null)
1026 statusHandler(this, EventArgs.Empty);