namespace System.Workflow.Activities { using System; using System.Text; using System.Reflection; using System.Collections; using System.CodeDom; using System.ComponentModel; using System.ComponentModel.Design; using System.Diagnostics; using System.Drawing; using System.Drawing.Design; using System.Drawing.Drawing2D; using System.Security; using System.Security.Permissions; using System.Workflow.Activities; using System.Workflow.ComponentModel; using System.Workflow.ComponentModel.Design; using System.Windows.Forms; using System.Windows.Forms.Design; #region Class SetStateDesigner [ActivityDesignerTheme(typeof(SetStateDesignerTheme))] [System.Runtime.InteropServices.ComVisible(false)] internal sealed class SetStateDesigner : ActivityDesigner { #region Fields private string previousTargetState = String.Empty; private Size targetStateSize = Size.Empty; #endregion Fields #region Properties #region Protected Properties protected override Rectangle TextRectangle { get { Size margin = WorkflowTheme.CurrentTheme.AmbientTheme.Margin; Rectangle textRectangle = base.TextRectangle; textRectangle.Offset(0, (-targetStateSize.Height - margin.Height) / 2); return textRectangle; } } protected override Rectangle ImageRectangle { get { Size margin = WorkflowTheme.CurrentTheme.AmbientTheme.Margin; Rectangle imageRectangle = base.ImageRectangle; imageRectangle.Offset(0, (-targetStateSize.Height - margin.Height) / 2); return imageRectangle; } } #endregion #region Private Properties private string TargetState { get { SetStateActivity setState = this.Activity as SetStateActivity; if (setState == null) return String.Empty; string targetState = setState.TargetStateName; if (targetState == null) return String.Empty; return targetState; } } /// /// Gets the value of text rectangle in logical coordinates. /// internal Rectangle TargetStateRectangle { get { Size margin = WorkflowTheme.CurrentTheme.AmbientTheme.Margin; Rectangle bounds = this.Bounds; Rectangle textRectangle = this.TextRectangle; Point location = new Point( bounds.Left + margin.Width, textRectangle.Bottom + (margin.Height / 2)); Size size = new Size( bounds.Width - margin.Width * 2, targetStateSize.Height); return new Rectangle(location, size); } } #endregion Private Properties #endregion Properties #region Methods #region Public Methods public override bool CanBeParentedTo(CompositeActivityDesigner parentActivityDesigner) { if (parentActivityDesigner == null) throw new ArgumentNullException("parentActivityDesigner"); CompositeActivity parentActivity = parentActivityDesigner.Activity as CompositeActivity; if (parentActivity == null) return false; bool result = ValidateParent(parentActivity); if (!result) return false; return base.CanBeParentedTo(parentActivityDesigner); } #endregion Public Methods #region Protected Methods protected override void OnActivityChanged(ActivityChangedEventArgs e) { base.OnActivityChanged(e); if (previousTargetState != this.TargetState) PerformLayout(); } /// /// Called to set the size of the visual cues or designers contained within the designer. /// /// ActivityDesignerLayoutEventArgs holding layout arguments protected override Size OnLayoutSize(ActivityDesignerLayoutEventArgs e) { Size size = base.OnLayoutSize(e); string targetState = this.TargetState; if (String.IsNullOrEmpty(targetState)) { // We use a dummy string so we don't // calculate an empty rectangle targetState = "M"; } Font font = e.DesignerTheme.Font; this.targetStateSize = StateMachineDesignerPaint.MeasureString(e.Graphics, font, targetState, StringAlignment.Near, Size.Empty); size.Height += targetStateSize.Height; return size; } protected override void OnPaint(ActivityDesignerPaintEventArgs e) { base.OnPaint(e); string targetState = this.TargetState; ActivityDesignerPaint.DrawText(e.Graphics, e.DesignerTheme.Font, targetState, this.TargetStateRectangle, StringAlignment.Center, e.AmbientTheme.TextQuality, e.DesignerTheme.ForegroundBrush); } #endregion Protected Methods #region Static Private Methods static private bool ValidateParent(CompositeActivity parentActivity) { if (parentActivity == null) return false; if (SetStateValidator.IsValidContainer(parentActivity)) return true; return ValidateParent(parentActivity.Parent); } #endregion Static Private Methods #endregion Methods } #endregion #region SetStateDesignerTheme internal sealed class SetStateDesignerTheme : ActivityDesignerTheme { public SetStateDesignerTheme(WorkflowTheme theme) : base(theme) { this.ForeColor = Color.FromArgb(0xFF, 0x00, 0x00, 0x00); this.BorderColor = Color.FromArgb(0xFF, 0x80, 0x80, 0x80); this.BorderStyle = DashStyle.Solid; this.BackColorStart = Color.FromArgb(0xFF, 0xF4, 0xF4, 0xF4); this.BackColorEnd = Color.FromArgb(0xFF, 0xC0, 0xC0, 0xC0); this.BackgroundStyle = LinearGradientMode.Horizontal; } } #endregion #region Class StateDropDownEditor internal sealed class StateDropDownEditor : UITypeEditor { #region Fields private IWindowsFormsEditorService _editorService; private ITypeDescriptorContext _context; private object _selectedObject; #endregion Fields #region Constructors/Destructors public StateDropDownEditor() { } #endregion Constructors/Destructors #region Methods #region Public Methods public override object EditValue(ITypeDescriptorContext typeDescriptorContext, IServiceProvider serviceProvider, object value) { if (typeDescriptorContext == null) throw new ArgumentNullException("typeDescriptorContext"); if (serviceProvider == null) throw new ArgumentNullException("serviceProvider"); _editorService = (IWindowsFormsEditorService)serviceProvider.GetService(typeof(IWindowsFormsEditorService)); _context = typeDescriptorContext; // Initialize the dropdown control ListBox dropDownList = new ListBox(); dropDownList.BorderStyle = BorderStyle.None; Activity activity = _context.Instance as Activity; if (activity == null) { // this could happen when there are multiple // SetState activities selected object[] activities = _context.Instance as object[]; if (activities != null && activities.Length > 0) activity = (Activity)activities[0]; } Debug.Assert(activity != null); // Add the items from the typeconverter, followed by the datasource choices PopulateDropDownList(dropDownList, activity); dropDownList.SelectedIndexChanged += new EventHandler(dataSourceDropDown_SelectedIndexChanged); // Display the control _editorService.DropDownControl(dropDownList); // If a value was selected, read the selected value from the control and return it if (dropDownList.SelectedIndex != -1 && _selectedObject != null) return _selectedObject; return value; } public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext typeDescriptorContext) { return UITypeEditorEditStyle.DropDown; } #endregion Public Methods #region Private Methods private void dataSourceDropDown_SelectedIndexChanged(object sender, EventArgs e) { _editorService.CloseDropDown(); _selectedObject = null; ListBox dropDownList = sender as ListBox; if (dropDownList == null) throw new ArgumentNullException("sender"); if (dropDownList.SelectedIndex < 0) return; _selectedObject = dropDownList.Items[dropDownList.SelectedIndex]; } private void PopulateDropDownList(ListBox dropDownList, Activity activity) { Debug.Assert(dropDownList != null); Debug.Assert(activity != null); StateActivity enclosingState = StateMachineHelpers.FindEnclosingState(activity); if (enclosingState == null) return; StateActivity rootState = StateMachineHelpers.GetRootState(enclosingState); FindStates(dropDownList, rootState); } private void FindStates(ListBox dropDownList, StateActivity parent) { foreach (Activity activity in parent.EnabledActivities) { StateActivity state = activity as StateActivity; if (state != null) { if (StateMachineHelpers.IsLeafState(state)) { dropDownList.Items.Add(state.QualifiedName); } else { FindStates(dropDownList, state); } } } } #endregion Private Methods #endregion Methods } #endregion Class StateDropDownEditor }