using System; using System.ComponentModel; using System.Drawing; using System.Windows.Forms; namespace Microsoft.Win32.TaskScheduler { /// /// Dialog that allows tasks to be edited /// [ToolboxItem(true), ToolboxItemFilter("System.Windows.Forms"), Description("Dialog allowing the editing of a task.")] [Designer("System.ComponentModel.Design.ComponentDesigner, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")] [DefaultProperty("Editable"), DesignTimeVisible(true)] [System.Drawing.ToolboxBitmap(typeof(TaskEditDialog), "TaskDialog")] public partial class TaskOptionsEditor : #if DEBUG Form #else DialogBase #endif , ITaskEditor { private OptionPanels.OptionPanel curPanel; private bool editable, onAssignment; private int hoverIndex = -1; private System.Collections.Generic.Dictionary panels = new System.Collections.Generic.Dictionary(10); private Task task; private TaskScheduler.TaskDefinition td; private bool titleSet; /// /// Initializes a new instance of the class. /// public TaskOptionsEditor() { InitializeComponent(); panels.Add(generalItem, new OptionPanels.GeneralOptionPanel()); panels.Add(triggersItem, new OptionPanels.TriggersOptionPanel()); panels.Add(actionsItem, new OptionPanels.ActionsOptionPanel()); panels.Add(securityItem, new OptionPanels.SecurityOptionPanel()); panels.Add(startupItem, new OptionPanels.StartupOptionPanel()); panels.Add(runItem, new OptionPanels.RuntimeOptionPanel()); foreach (var p in menuItemsContainer.Items) menuList.Items.Add(p); UpdateTitleFont(); } /// /// Initializes a new instance of the class. /// /// The task. /// If set to true the task will be editable in the dialog. /// If set to true the task will be registered when Ok is pressed. public TaskOptionsEditor(Task task, bool editable = true, bool registerOnAccept = true) : this() { this.Editable = editable; this.Initialize(task); this.RegisterTaskOnAccept = registerOnAccept; } /// /// Initializes a new instance of the class. /// /// A instance. /// An optional . Leaving null creates a new task. /// If set to true the task will be editable in the dialog. /// If set to true the task will be registered when Ok is pressed. public TaskOptionsEditor(TaskService service, TaskDefinition td = null, bool editable = true, bool registerOnAccept = true) : this() { this.Editable = editable; this.Initialize(service, td); this.RegisterTaskOnAccept = registerOnAccept; } /// /// Gets or sets a value indicating whether this is editable. /// /// true if editable; otherwise, false. [DefaultValue(false), Category("Behavior"), Description("Determines whether the task can be edited.")] public bool Editable { get { return editable; } set { if (editable != value) { editable = value; ReinitializeControls(); } } } /// /// Gets or sets a value indicating whether this task definition is v2. /// /// /// true if this task definition is v2; otherwise, false. /// [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public bool IsV2 { get; private set; } /// /// Gets or sets a value indicating whether to register task when Accept (Ok) button pressed. /// /// true if updated task is to be registered; otherwise, false. [Category("Behavior"), DefaultValue(false)] public bool RegisterTaskOnAccept { get; set; } /// /// Gets or sets a value indicating whether errors are shown in the UI. /// /// /// true if errors are shown; otherwise, false. /// [DefaultValue(true), Category("Behavior"), Description("Determines whether errors are shown in the UI.")] public bool ShowErrors { get; set; } /// /// Gets the current . This is only the task used to initialize this control. The updates made to the control are not registered. /// /// The task. [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public Task Task { get { return task; } private set { task = value; if (task != null) { TaskService = task.TaskService; if (task.ReadOnly) this.Editable = false; TaskDefinition = task.Definition; } } } /// /// Gets the in its edited state. /// /// The task definition. [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public TaskDefinition TaskDefinition { get { return td; } private set { if (TaskService == null) throw new ArgumentNullException("TaskDefinition cannot be set until TaskService has been set with a valid object."); if (value == null) throw new ArgumentNullException("TaskDefinition cannot be set to null."); onAssignment = true; td = value; IsV2 = td.Settings.Compatibility >= TaskCompatibility.V2; taskNameText.Text = this.Task != null ? this.Task.Name : string.Empty; SetVersionComboItems(); ReinitializeControls(); onAssignment = false; } } /// /// Gets or sets the folder for the task. If control is initialized with a , this value will be set to the folder of the registered task. /// /// The task folder name. [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public string TaskFolder { get; set; } /// /// Gets or sets the name of the task. If control is initialized with a , this value will be set to the name of the registered task. /// /// The task name. [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public string TaskName { get; set; } /// /// Gets the assigned at initialization. /// /// The task service. [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public TaskService TaskService { get; set; } /// /// Gets or sets the title. /// /// The title. [Category("Appearance"), Description("A string to display in the title bar of the dialog box."), Localizable(true)] public string Title { get { return base.Text; } set { base.Text = value; titleSet = true; } } /// /// Initializes the control for the editing of a new . /// /// A instance. /// An optional . Leaving null creates a new task. public void Initialize(TaskService service, TaskDefinition td = null) { if (service == null) throw new ArgumentNullException("service"); if (!titleSet) this.Text = string.Format(EditorProperties.Resources.TaskEditDlgTitle, "New Task", TaskEditDialog.GetServerString(service)); this.TaskService = service; this.task = null; if (!this.IsDesignMode()) { if (td == null) this.TaskDefinition = service.NewTask(); else this.TaskDefinition = td; } } /// /// Initializes the control for the editing of an existing . /// /// A instance. public void Initialize(Task task) { if (task == null) throw new ArgumentNullException("task"); if (!titleSet) this.Text = string.Format(EditorProperties.Resources.TaskEditDlgTitle, task.Name, TaskEditDialog.GetServerString(task.TaskService)); this.Task = task; } /// /// Reinitializes all the controls based on current values. /// public void ReinitializeControls() { taskNameText.ReadOnly = !(this.Task == null && this.Editable); taskVersionCombo.Enabled = this.Editable; if (curPanel == null && td != null) //this.menuList.Items[0].PerformClick(); this.menuList.SelectedIndex = 0; if (curPanel != null) curPanel.Initialize(this); } /// /// Raises the event when the property value of the control's container changes. /// /// An that contains the event data. protected override void OnParentFontChanged(EventArgs e) { base.OnParentFontChanged(e); UpdateTitleFont(); } private void cancelButton_Click(object sender, EventArgs e) { Close(); } private void menuItem_Click(object sender, EventArgs e) { if (sender is ToolStripMenuItem) { OptionPanels.OptionPanel panel = null; if (panels.TryGetValue((ToolStripMenuItem)sender, out panel)) { this.bodyPanel.SuspendLayout(); panel.Dock = DockStyle.Fill; this.panelTitleLabel.Text = panel.Title; this.panelImage.Image = panel.Image; this.panelImage.Visible = panel.Image != null; if (curPanel != null) this.bodyPanel.Controls.Remove(curPanel); this.bodyPanel.Controls.Add(panel); this.bodyPanel.Controls.SetChildIndex(panel, 0); curPanel = panel; if (td != null) panel.Initialize(this); this.bodyPanel.ResumeLayout(); } } } private void menuList_DrawItem(object sender, DrawItemEventArgs e) { Color sel = SystemColors.ControlLight; Color hot = LightenColor(SystemColors.ControlLight, 50); Color fc = this.ForeColor; Color bc = SystemColors.Window; if ((e.State & DrawItemState.Selected) == DrawItemState.Selected) bc = sel; if (e.Index == hoverIndex) bc = hot; if ((e.State & DrawItemState.Grayed) == DrawItemState.Grayed) fc = SystemColors.GrayText; using (Brush bgb = new SolidBrush(bc)) e.Graphics.FillRectangle(bgb, e.Bounds); TextRenderer.DrawText(e.Graphics, menuList.Items[e.Index].ToString(), this.Font, AdjustRect(e.Bounds, 4, 0, -4, 0), fc, bc, TextFormatFlags.EndEllipsis | TextFormatFlags.VerticalCenter); if ((e.State & DrawItemState.Focus) == DrawItemState.Focus) using (Pen bgb = new Pen(sel)) e.Graphics.DrawRectangle(bgb, AdjustRect(e.Bounds, 0, 0, -1, -1)); } private static Color LightenColor(Color colorIn, int percent) { if (percent < 0 || percent > 100) throw new ArgumentOutOfRangeException("percent"); return Color.FromArgb(colorIn.A, colorIn.R + (int)(((255f - colorIn.R) / 100f) * percent), colorIn.G + (int)(((255f - colorIn.G) / 100f) * percent), colorIn.B + (int)(((255f - colorIn.B) / 100f) * percent)); } private static Rectangle AdjustRect(Rectangle rect, int x, int y = 0, int w = 0, int h = 0) { return new Rectangle(rect.X + x, rect.Y + y, rect.Width + w, rect.Height + h); } private void menuList_MeasureItem(object sender, MeasureItemEventArgs e) { e.ItemHeight *= 2; } private void menuList_MouseMove(object sender, MouseEventArgs e) { int index = menuList.IndexFromPoint(e.Location); if (index != hoverIndex) { hoverIndex = index; menuList.Invalidate(); } } private void menuList_MouseLeave(object sender, EventArgs e) { if (hoverIndex > -1) { hoverIndex = -1; menuList.Invalidate(); } } private void menuList_SelectedIndexChanged(object sender, EventArgs e) { menuItem_Click(menuList.SelectedItem as ToolStripMenuItem, EventArgs.Empty); } private void okButton_Click(object sender, EventArgs e) { if (this.TaskDefinition.Actions.Count == 0) { MessageBox.Show(EditorProperties.Resources.TaskMustHaveActionsError, null, MessageBoxButtons.OK, MessageBoxIcon.Error); return; } if (this.TaskDefinition.Settings.DeleteExpiredTaskAfter != TimeSpan.Zero && !TaskEditDialog.ValidateOneTriggerExpires(this.TaskDefinition.Triggers)) { MessageBox.Show(EditorProperties.Resources.Error_TaskDeleteMustHaveExpiringTrigger, null, MessageBoxButtons.OK, MessageBoxIcon.Error); return; } if (this.TaskDefinition.LowestSupportedVersion > this.TaskDefinition.Settings.Compatibility) { MessageBox.Show(EditorProperties.Resources.Error_TaskPropertiesIncompatibleSimple, null, MessageBoxButtons.OK, MessageBoxIcon.Error); return; } if (RegisterTaskOnAccept) { if (this.Task != null && this.Task.Definition.Principal.LogonType != TaskLogonType.InteractiveTokenOrPassword && this.Task.Definition.Principal.LogonType != TaskLogonType.Password) this.Task.RegisterChanges(); else { string user = this.TaskDefinition.Principal.ToString(); string pwd = null; TaskFolder fld = this.TaskService.GetFolder(this.TaskFolder); if (this.TaskDefinition.Principal.LogonType == TaskLogonType.InteractiveTokenOrPassword || this.TaskDefinition.Principal.LogonType == TaskLogonType.Password) { pwd = TaskEditDialog.InvokeCredentialDialog(user, this); if (pwd == null) { //throw new System.Security.Authentication.AuthenticationException(EditorProperties.Resources.UserAuthenticationError); MessageBox.Show(EditorProperties.Resources.Error_PasswordMustBeProvided, null, MessageBoxButtons.OK, MessageBoxIcon.Error); return; } } this.Task = fld.RegisterTaskDefinition(this.TaskName, this.TaskDefinition, TaskCreation.CreateOrUpdate, user, pwd, this.TaskDefinition.Principal.LogonType); } } this.DialogResult = DialogResult.OK; Close(); } private void ResetTitle() { System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(TaskOptionsEditor)); base.Text = resources.GetString("$this.Text"); } private bool ShouldSerializeTitle() { System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(TaskOptionsEditor)); return base.Text != resources.GetString("$this.Text"); } private void SetVersionComboItems() { const int expectedVersions = 5; this.taskVersionCombo.BeginUpdate(); this.taskVersionCombo.Items.Clear(); string[] versions = EditorProperties.Resources.TaskCompatibility.Split('|'); if (versions.Length != expectedVersions) throw new ArgumentOutOfRangeException("Locale specific information about supported Operating Systems is insufficient."); int max = (this.TaskService == null) ? expectedVersions - 1 : TaskService.LibraryVersion.Minor; TaskCompatibility comp = (td != null) ? td.Settings.Compatibility : TaskCompatibility.V1; TaskCompatibility lowestComp = (td != null) ? td.LowestSupportedVersion : TaskCompatibility.V1; switch (comp) { case TaskCompatibility.AT: for (int i = max; i > 1; i--) this.taskVersionCombo.Items.Add(new ComboItem(versions[i], i, comp >= lowestComp)); this.taskVersionCombo.SelectedIndex = this.taskVersionCombo.Items.Add(new ComboItem(versions[0], 0)); break; default: for (int i = max; i > 0; i--) this.taskVersionCombo.Items.Add(new ComboItem(versions[i], i, comp >= lowestComp)); this.taskVersionCombo.SelectedIndex = this.taskVersionCombo.Items.IndexOf((int)comp); break; } this.taskVersionCombo.EndUpdate(); } private void taskNameText_Validating(object sender, System.ComponentModel.CancelEventArgs e) { char[] inv = System.IO.Path.GetInvalidFileNameChars(); e.Cancel = !ValidateText(taskNameText, delegate(string s) { return s.Length > 0 && s.IndexOfAny(inv) == -1; }, EditorProperties.Resources.Error_InvalidNameFormat); } private void TaskOptionsEditor_HelpButtonClicked(object sender, CancelEventArgs e) { } private void taskVersionCombo_SelectedIndexChanged(object sender, EventArgs e) { IsV2 = taskVersionCombo.SelectedIndex == -1 ? true : ((ComboItem)taskVersionCombo.SelectedItem).Version > 1; TaskCompatibility priorSetting = (td != null) ? td.Settings.Compatibility : TaskCompatibility.V1; if (!onAssignment && td != null && taskVersionCombo.SelectedIndex != -1) td.Settings.Compatibility = (TaskCompatibility)((ComboItem)taskVersionCombo.SelectedItem).Version; try { if (!onAssignment && td != null) { td.Validate(true); ReinitializeControls(); } } catch (InvalidOperationException ex) { var msg = new System.Text.StringBuilder(); if (this.ShowErrors) { msg.AppendLine(EditorProperties.Resources.Error_TaskPropertiesIncompatible); foreach (var item in ex.Data.Keys) msg.AppendLine(string.Format("- {0} {1}", item, ex.Data[item])); } else msg.Append(EditorProperties.Resources.Error_TaskPropertiesIncompatibleSimple); MessageBox.Show(this, msg.ToString(), EditorProperties.Resources.TaskSchedulerName, MessageBoxButtons.OK, MessageBoxIcon.Error); this.taskVersionCombo.SelectedIndex = this.taskVersionCombo.Items.IndexOf((int)priorSetting); return; } } private void UpdateTitleFont() { this.panelTitleLabel.Font = new System.Drawing.Font(this.Font.FontFamily, this.Font.Size + 1, System.Drawing.FontStyle.Bold, this.Font.Unit); } private bool ValidateText(Control ctrl, Predicate pred, string error) { bool valid = pred(ctrl.Text); //errorProvider.SetError(ctrl, valid ? string.Empty : error); //OnComponentError(valid ? ComponentErrorEventArgs.Empty : new ComponentErrorEventArgs(null, error)); //hasError = valid; return valid; } private class ComboItem : IEnableable { public string Text; public int Version; private bool enabled; public ComboItem(string text, int ver, bool enabled = true) { Text = text; Version = ver; this.enabled = enabled; } public bool Enabled { get { return enabled; } set { enabled = value; } } public override bool Equals(object obj) { if (obj is ComboItem) return Version == ((ComboItem)obj).Version; if (obj is int) return Version == (int)obj; return Text.CompareTo(obj.ToString()) == 0; } public override int GetHashCode() { return Version.GetHashCode(); } public override string ToString() { return this.Text; } } } }