using DevExpress.Utils; using DevExpress.Utils.Controls; using DevExpress.Utils.Internal; using DevExpress.Utils.Menu; using DevExpress.Utils.Svg; using DevExpress.XtraEditors; using DevExpress.XtraEditors.Controls; using DevExpress.XtraEditors.Native; using DevExpress.XtraScheduler; using DevExpress.XtraScheduler.Internal; using DevExpress.XtraScheduler.Localization; using DevExpress.XtraScheduler.Native; using DevExpress.XtraScheduler.UI; using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Reflection; using System.Windows.Forms; namespace HL_FristAidPlatform_PreHospitalEmergency { public partial class CustomAppointmentForm1 : XtraForm, IDXManagerPopupMenu { bool openRecurrenceForm; readonly ISchedulerStorage storage; readonly SchedulerControl control; SvgImage recurringSvgImage; SvgImage normalSvgImage; readonly AppointmentFormController controller; IDXMenuManager menuManager; [EditorBrowsable(EditorBrowsableState.Never)] public CustomAppointmentForm1() { InitializeComponent(); } public CustomAppointmentForm1(SchedulerControl control, Appointment apt) : this(control, apt, false) { } public CustomAppointmentForm1(SchedulerControl control, Appointment apt, bool openRecurrenceForm) { Guard.ArgumentNotNull(control, "control"); Guard.ArgumentNotNull(control.DataStorage, "control.DataStorage"); Guard.ArgumentNotNull(apt, "apt"); this.openRecurrenceForm = openRecurrenceForm; this.controller = CreateController(control, apt); // // Required for Windows Form Designer support // InitializeComponent(); SetupPredefinedConstraints(); LoadIcons(); this.control = control; this.storage = control.DataStorage; this.edtShowTimeAs.Storage = this.storage; this.edtLabel.Storage = this.storage; this.edtResource.SchedulerControl = control; this.edtResource.Storage = this.storage; this.edtResources.SchedulerControl = control; SubscribeControllerEvents(Controller); SubscribeEditorsEvents(); BindControllerToControls(); } protected override FormShowMode ShowMode { get { return FormShowMode.AfterInitialization; } } [Browsable(false)] public IDXMenuManager MenuManager { get { return this.menuManager; } private set { this.menuManager = value; } } protected internal AppointmentFormController Controller { get { return this.controller; } } protected internal SchedulerControl Control { get { return this.control; } } protected internal ISchedulerStorage Storage { get { return this.storage; } } protected internal bool IsNewAppointment { get { return this.controller != null ? this.controller.IsNewAppointment : true; } } protected internal SvgImage RecurringSvgImage { get { return this.recurringSvgImage; } } protected internal SvgImage NormalSvgImage { get { return this.normalSvgImage; } } [Browsable(false), EditorBrowsable(EditorBrowsableState.Never), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public SvgImage SvgImage { get { return IconOptions.SvgImage; } set { IconOptions.SvgImage = value; } } protected internal bool OpenRecurrenceForm { get { return this.openRecurrenceForm; } } [DXDescription("DevExpress.XtraScheduler.UI.AppointmentForm,ReadOnly")] [DXCategory(CategoryName.Behavior)] [DefaultValue(false)] public bool ReadOnly { get { return Controller != null && Controller.ReadOnly; } set { if (Controller.ReadOnly == value) return; Controller.ReadOnly = value; } } public virtual void LoadFormData(Appointment appointment) { //do nothing } public virtual bool SaveFormData(Appointment appointment) { return true; } public virtual bool IsAppointmentChanged(Appointment appointment) { return false; } public virtual void SetMenuManager(IDXMenuManager menuManager) { MenuManagerUtils.SetMenuManager(Controls, menuManager); this.menuManager = menuManager; } protected internal virtual void SetupPredefinedConstraints() { this.tbProgress.Properties.Minimum = AppointmentProcessValues.Min; this.tbProgress.Properties.Maximum = AppointmentProcessValues.Max; this.tbProgress.Properties.SmallChange = AppointmentProcessValues.Step; this.edtResources.Visible = true; } protected virtual void BindControllerToControls() { BindControllerToIcon(); BindProperties(this.tbSubject, "Text", "Subject"); BindProperties(this.tbLocation, "Text", "Location"); BindProperties(this.tbDescription, "Text", "Description"); BindProperties(this.edtShowTimeAs, "Status", "Status"); BindProperties(this.edtStartDate, "EditValue", "DisplayStartDate"); BindProperties(this.edtStartDate, "Enabled", "IsDateTimeEditable"); BindProperties(this.edtStartTime, "EditValue", "DisplayStartTime"); BindProperties(this.edtStartTime, "Visible", "IsTimeVisible"); BindProperties(this.edtStartTime, "Enabled", "IsTimeVisible"); BindProperties(this.edtEndDate, "EditValue", "DisplayEndDate", DataSourceUpdateMode.Never); BindProperties(this.edtEndDate, "Enabled", "IsDateTimeEditable", DataSourceUpdateMode.Never); BindProperties(this.edtEndTime, "EditValue", "DisplayEndTime", DataSourceUpdateMode.Never); BindProperties(this.edtEndTime, "Visible", "IsTimeVisible", DataSourceUpdateMode.Never); BindProperties(this.edtEndTime, "Enabled", "IsTimeVisible", DataSourceUpdateMode.Never); BindProperties(this.chkAllDay, "Checked", "AllDay"); BindProperties(this.chkAllDay, "Enabled", "IsDateTimeEditable"); BindProperties(this.edtResource, "ResourceId", "ResourceId"); BindProperties(this.edtResource, "Enabled", "CanEditResource"); BindToBoolPropertyAndInvert(this.edtResource, "Visible", "ResourceSharing"); BindProperties(this.edtResources, "ResourceIds", "ResourceIds"); BindProperties(this.edtResources, "Visible", "ResourceSharing"); BindProperties(this.edtResources, "Enabled", "CanEditResource"); BindProperties(this.lblResource, "Enabled", "CanEditResource"); BindProperties(this.edtLabel, "Label", "Label"); BindProperties(this.chkReminder, "Enabled", "ReminderVisible"); BindProperties(this.chkReminder, "Visible", "ReminderVisible"); BindProperties(this.chkReminder, "Checked", "HasReminder"); BindProperties(this.cbReminder, "Enabled", "HasReminder"); BindProperties(this.cbReminder, "Visible", "ReminderVisible"); BindProperties(this.cbReminder, "Duration", "ReminderTimeBeforeStart"); BindProperties(this.tbProgress, "Value", "PercentComplete"); BindProperties(this.lblPercentCompleteValue, "Text", "PercentComplete", ObjectToStringConverter); BindProperties(this.progressPanel, "Visible", "ShouldEditTaskProgress"); BindToBoolPropertyAndInvert(this.btnOk, "Enabled", "ReadOnly"); BindToBoolPropertyAndInvert(this.btnRecurrence, "Enabled", "ReadOnly"); BindProperties(this.btnDelete, "Enabled", "CanDeleteAppointment"); BindProperties(this.btnRecurrence, "Visible", "ShouldShowRecurrenceButton"); } protected virtual void BindControllerToIcon() { Binding binding = new Binding("SvgImage", Controller, "AppointmentType"); binding.Format += AppointmentTypeToIconConverter; DataBindings.Add(binding); } protected virtual void ObjectToStringConverter(object o, ConvertEventArgs e) { e.Value = e.Value.ToString(); } protected virtual void AppointmentTypeToIconConverter(object o, ConvertEventArgs e) { AppointmentType type = (AppointmentType)e.Value; if (type == AppointmentType.Pattern) e.Value = RecurringSvgImage; else e.Value = NormalSvgImage; } protected virtual void BindProperties(Control target, string targetProperty, string sourceProperty) { BindProperties(target, targetProperty, sourceProperty, DataSourceUpdateMode.OnPropertyChanged); } protected virtual void BindProperties(Control target, string targetProperty, string sourceProperty, DataSourceUpdateMode updateMode) { target.DataBindings.Add(targetProperty, Controller, sourceProperty, true, updateMode); } protected virtual void BindProperties(Control target, string targetProperty, string sourceProperty, ConvertEventHandler objectToStringConverter) { Binding binding = new Binding(targetProperty, Controller, sourceProperty, true); binding.Format += objectToStringConverter; target.DataBindings.Add(binding); } protected virtual void BindToBoolPropertyAndInvert(Control target, string targetProperty, string sourceProperty) { target.DataBindings.Add(new BoolInvertBinding(targetProperty, Controller, sourceProperty)); } protected override void OnLoad(EventArgs e) { base.OnLoad(e); if (Controller == null) return; DataBindings.Add("Text", Controller, "Caption"); SubscribeControlsEvents(); LoadFormData(Controller.EditedAppointmentCopy); RecalculateLayoutOfControlsAffectedByProgressPanel(); } protected virtual AppointmentFormController CreateController(SchedulerControl control, Appointment apt) { return new AppointmentFormController(control, apt); } void SubscribeEditorsEvents() { this.cbReminder.EditValueChanging += OnCbReminderEditValueChanging; } void SubscribeControllerEvents(AppointmentFormController controller) { if (controller == null) return; controller.PropertyChanged += OnControllerPropertyChanged; } void OnControllerPropertyChanged(object sender, PropertyChangedEventArgs e) { if (e.PropertyName == "ReadOnly") UpdateReadonly(); } protected virtual void UpdateReadonly() { if (Controller == null) return; IList controls = GetAllControls(this); foreach (Control control in controls) { BaseEdit editor = control as BaseEdit; if (editor == null) continue; editor.ReadOnly = Controller.ReadOnly; } this.btnOk.Enabled = !Controller.ReadOnly; this.btnRecurrence.Enabled = !Controller.ReadOnly; } List GetAllControls(Control rootControl) { List result = new List(); foreach (Control control in rootControl.Controls) { result.Add(control); IList childControls = GetAllControls(control); result.AddRange(childControls); } return result; } protected internal virtual void LoadIcons() { Assembly asm = typeof(Appointment).Assembly; this.recurringSvgImage = ResourceImageHelper.CreateSvgImageFromResources(SchedulerSvgImageNames.NewRecurringAppointment, asm); this.normalSvgImage = ResourceImageHelper.CreateSvgImageFromResources(SchedulerSvgImageNames.NewAppointment, asm); } protected internal virtual void SubscribeControlsEvents() { this.edtEndDate.Validating += new CancelEventHandler(OnEdtEndDateValidating); this.edtEndDate.InvalidValue += new InvalidValueExceptionEventHandler(OnEdtEndDateInvalidValue); this.edtEndTime.Validating += new CancelEventHandler(OnEdtEndTimeValidating); this.edtEndTime.InvalidValue += new InvalidValueExceptionEventHandler(OnEdtEndTimeInvalidValue); this.cbReminder.InvalidValue += new InvalidValueExceptionEventHandler(OnCbReminderInvalidValue); this.cbReminder.Validating += new CancelEventHandler(OnCbReminderValidating); this.edtStartDate.Validating += new CancelEventHandler(OnEdtStartDateValidating); this.edtStartDate.InvalidValue += new InvalidValueExceptionEventHandler(OnEdtStartDateInvalidValue); this.edtStartTime.Validating += new CancelEventHandler(OnEdtStartTimeValidating); this.edtStartTime.InvalidValue += new InvalidValueExceptionEventHandler(OnEdtStartTimeInvalidValue); } protected internal virtual void UnsubscribeControlsEvents() { this.edtEndDate.Validating -= new CancelEventHandler(OnEdtEndDateValidating); this.edtEndDate.InvalidValue -= new InvalidValueExceptionEventHandler(OnEdtEndDateInvalidValue); this.edtEndTime.Validating -= new CancelEventHandler(OnEdtEndTimeValidating); this.edtEndTime.InvalidValue -= new InvalidValueExceptionEventHandler(OnEdtEndTimeInvalidValue); this.cbReminder.InvalidValue -= new InvalidValueExceptionEventHandler(OnCbReminderInvalidValue); this.cbReminder.Validating -= new CancelEventHandler(OnCbReminderValidating); this.edtStartDate.Validating -= new CancelEventHandler(OnEdtStartDateValidating); this.edtStartDate.InvalidValue -= new InvalidValueExceptionEventHandler(OnEdtStartDateInvalidValue); this.edtStartTime.Validating -= new CancelEventHandler(OnEdtStartTimeValidating); this.edtStartTime.InvalidValue -= new InvalidValueExceptionEventHandler(OnEdtStartTimeInvalidValue); } void OnBtnOkClick(object sender, EventArgs e) { OnOkButton(); } protected internal virtual void OnEdtStartTimeInvalidValue(object sender, InvalidValueExceptionEventArgs e) { e.ErrorText = SchedulerLocalizer.GetString(SchedulerStringId.Msg_DateOutsideLimitInterval); } protected internal virtual void OnEdtStartTimeValidating(object sender, CancelEventArgs e) { e.Cancel = !Controller.ValidateLimitInterval(this.edtStartDate.DateTime.Date, this.edtStartTime.Time.TimeOfDay, this.edtEndDate.DateTime.Date, this.edtEndTime.Time.TimeOfDay); } protected internal virtual void OnEdtStartDateInvalidValue(object sender, InvalidValueExceptionEventArgs e) { e.ErrorText = SchedulerLocalizer.GetString(SchedulerStringId.Msg_DateOutsideLimitInterval); } protected internal virtual void OnEdtStartDateValidating(object sender, CancelEventArgs e) { e.Cancel = !Controller.ValidateLimitInterval(this.edtStartDate.DateTime.Date, this.edtStartTime.Time.TimeOfDay, this.edtEndDate.DateTime.Date, this.edtEndTime.Time.TimeOfDay); } protected internal virtual void OnEdtEndDateValidating(object sender, CancelEventArgs e) { e.Cancel = !IsValidInterval(); if (!e.Cancel) this.edtEndDate.DataBindings["EditValue"].WriteValue(); } protected internal virtual void OnEdtEndDateInvalidValue(object sender, InvalidValueExceptionEventArgs e) { if (!AppointmentFormControllerBase.ValidateInterval(this.edtStartDate.DateTime.Date, this.edtStartTime.Time.TimeOfDay, this.edtEndDate.DateTime.Date, this.edtEndTime.Time.TimeOfDay)) e.ErrorText = SchedulerLocalizer.GetString(SchedulerStringId.Msg_InvalidEndDate); else e.ErrorText = SchedulerLocalizer.GetString(SchedulerStringId.Msg_DateOutsideLimitInterval); } protected internal virtual void OnEdtEndTimeValidating(object sender, CancelEventArgs e) { e.Cancel = !IsValidInterval(); if (!e.Cancel) this.edtEndTime.DataBindings["EditValue"].WriteValue(); } protected internal virtual void OnEdtEndTimeInvalidValue(object sender, InvalidValueExceptionEventArgs e) { if (!AppointmentFormControllerBase.ValidateInterval(this.edtStartDate.DateTime.Date, this.edtStartTime.Time.TimeOfDay, this.edtEndDate.DateTime.Date, this.edtEndTime.Time.TimeOfDay)) e.ErrorText = SchedulerLocalizer.GetString(SchedulerStringId.Msg_InvalidEndDate); else e.ErrorText = SchedulerLocalizer.GetString(SchedulerStringId.Msg_DateOutsideLimitInterval); } protected internal virtual bool IsValidInterval() { return AppointmentFormControllerBase.ValidateInterval(this.edtStartDate.DateTime.Date, this.edtStartTime.Time.TimeOfDay, this.edtEndDate.DateTime.Date, this.edtEndTime.Time.TimeOfDay) && Controller.ValidateLimitInterval(this.edtStartDate.DateTime.Date, this.edtStartTime.Time.TimeOfDay, this.edtEndDate.DateTime.Date, this.edtEndTime.Time.TimeOfDay); } protected internal virtual void OnOkButton() { if (!ValidateDateAndTime()) return; if (!SaveFormData(Controller.EditedAppointmentCopy)) return; if (!Controller.IsConflictResolved()) { ShowMessageBox(SchedulerLocalizer.GetString(SchedulerStringId.Msg_Conflict), Controller.GetMessageBoxCaption(SchedulerStringId.Msg_Conflict), MessageBoxButtons.OK, MessageBoxIcon.Exclamation); return; } if (!Controller.IsTimeValid()) { ShowMessageBox(SchedulerLocalizer.GetString(SchedulerStringId.Msg_InvalidAppointmentTime), Controller.GetMessageBoxCaption(SchedulerStringId.Msg_InvalidAppointmentTime), MessageBoxButtons.OK, MessageBoxIcon.Exclamation); return; } if (IsAppointmentChanged(Controller.EditedAppointmentCopy) || Controller.IsAppointmentChanged() || Controller.IsNewAppointment) Controller.ApplyChanges(); DialogResult = DialogResult.OK; } private bool ValidateDateAndTime() { this.edtEndDate.DoValidate(); this.edtEndTime.DoValidate(); this.edtStartDate.DoValidate(); this.edtStartTime.DoValidate(); return String.IsNullOrEmpty(this.edtEndTime.ErrorText) && String.IsNullOrEmpty(this.edtEndDate.ErrorText) && String.IsNullOrEmpty(this.edtStartDate.ErrorText) && String.IsNullOrEmpty(this.edtStartTime.ErrorText); } protected internal virtual DialogResult ShowMessageBox(string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon) { return XtraMessageBox.Show(this, text, caption, buttons, icon); } void OnBtnDeleteClick(object sender, EventArgs e) { OnDeleteButton(); } protected internal virtual void OnDeleteButton() { if (IsNewAppointment) return; Controller.DeleteAppointment(); DialogResult = DialogResult.Abort; Close(); } void OnBtnRecurrenceClick(object sender, EventArgs e) { OnRecurrenceButton(); } protected internal virtual void OnRecurrenceButton() { if (!Controller.ShouldShowRecurrenceButton) return; Appointment patternCopy = Controller.PrepareToRecurrenceEdit(); DialogResult result; using (Form form = CreateAppointmentRecurrenceForm(patternCopy, Control.OptionsView.FirstDayOfWeek)) { result = ShowRecurrenceForm(form); } if (result == DialogResult.Abort) { Controller.RemoveRecurrence(); } else if (result == DialogResult.OK) { Controller.ApplyRecurrence(patternCopy); } } protected virtual DialogResult ShowRecurrenceForm(Form form) { return FormTouchUIAdapter.ShowDialog(form, this); } protected internal virtual Form CreateAppointmentRecurrenceForm(Appointment patternCopy, FirstDayOfWeek firstDayOfWeek) { AppointmentRecurrenceForm form = new AppointmentRecurrenceForm(patternCopy, firstDayOfWeek, Controller); form.SetMenuManager(MenuManager); form.LookAndFeel.ParentLookAndFeel = LookAndFeel; form.ShowExceptionsRemoveMsgBox = this.controller.AreExceptionsPresent(); return form; } protected override void OnShown(EventArgs e) { base.OnShown(e); if (this.openRecurrenceForm) { this.openRecurrenceForm = false; OnRecurrenceButton(); } } protected internal virtual void OnCbReminderValidating(object sender, CancelEventArgs e) { TimeSpan span = this.cbReminder.Duration; e.Cancel = (span == TimeSpan.MinValue) || (span.Ticks < 0); if (!e.Cancel) this.cbReminder.DataBindings["Duration"].WriteValue(); } protected internal virtual void OnCbReminderInvalidValue(object sender, InvalidValueExceptionEventArgs e) { e.ErrorText = SchedulerLocalizer.GetString(SchedulerStringId.Msg_InvalidReminderTimeBeforeStart); } protected internal virtual void RecalculateLayoutOfControlsAffectedByProgressPanel() { if (this.progressPanel.Visible) return; int intDeltaY = this.progressPanel.Height; this.tbDescription.Location = new Point(this.tbDescription.Location.X, this.tbDescription.Location.Y - intDeltaY); this.tbDescription.Size = new Size(this.tbDescription.Size.Width, this.tbDescription.Size.Height + intDeltaY); } void OnCbReminderEditValueChanging(object sender, ChangingEventArgs e) { if (e.NewValue is TimeSpan) return; string stringValue = e.NewValue as String; TimeSpan duration = HumanReadableTimeSpanHelper.Parse(stringValue); if (duration.Ticks < 0) e.NewValue = TimeSpan.FromTicks(0); } } }