using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Data; using System.Linq; using System.Text; using System.Windows.Forms; using Inet.Viewer.Data; using System.Globalization; using System.Threading; using Inet.Viewer.Resources; namespace Inet.Viewer.WinForms.Prompt { /// /// A panel for date range prompts. /// public partial class DateRangePromptField : PromptControl { private static readonly PredefRange[] DefaultPredefRanges = { new YearToDatePredef(), new CurrentYearPredef(), new PreviousYearPredef(), new CurrentMonthPredef(), new PrevoiusMonthPredef(), new CurrentWeekPredef(), new PreviousWeekPredef(), }; private bool dateOnly; private DateTime currentDate0 = new DateTime(), currentDate1 = new DateTime(); private bool ignoreEvents = true; private List predefRanges; /// /// Creates a panel. /// /// prompt this panel is based on public DateRangePromptField(PromptData p) { this.PromptData = p; InitializeComponent(); dateOnly = p.Type == PromptData.Date; string dateFormat = dateOnly ? Thread.CurrentThread.CurrentCulture.DateTimeFormat.ShortDatePattern : Thread.CurrentThread.CurrentCulture.DateTimeFormat.ShortDatePattern + " " + Thread.CurrentThread.CurrentCulture.DateTimeFormat.ShortTimePattern; string dateFormatLong = dateOnly ? Thread.CurrentThread.CurrentCulture.DateTimeFormat.LongDatePattern : Thread.CurrentThread.CurrentCulture.DateTimeFormat.LongDatePattern + " " + Thread.CurrentThread.CurrentCulture.DateTimeFormat.ShortTimePattern; dtpFrom.CustomFormat = dtpTo.CustomFormat = dateFormatLong; for (int i = 1; i <= 53; i++) { cmbWeek.Items.Add(strings.CalendarWeek_Short+ ' ' + i); } int month = DateTime.Now.Month - 1; int year = DateTime.Now.Year; for (int y = year + 5; y >= year - 5; y--) { cmbYear.Items.Add(y.ToString()); } // setup comboboxes initially according to current date cmbQuarter.SelectedIndex = month / 3; cmbMonth.SelectedIndex = month; cmbWeek.SelectedIndex = WeekOfYear(DateTime.Now); cmbYear.Text = year.ToString(); int maxWidth = cmbPredefined.Width; predefRanges = new List(); List singleDefaults = new List(); foreach (PromptValue defaultValue in p.DefaultValues) { if (defaultValue is RangePromptValue) { RangePromptValue range = ((RangePromptValue)defaultValue); DateTime from = (DateTime)range.StartValue.Value; DateTime to = (DateTime)range.EndValue.Value; string text = from.ToString(dateFormat) + " - " + to.ToString(dateFormat); if (dateOnly) { to = Thread.CurrentThread.CurrentCulture.Calendar.AddDays(to, 1); } predefRanges.Add(new CustomPredef(text, from, to)); int w = TextRenderer.MeasureText(text, cmbPredefined.Font).Width + 20; if (w > maxWidth) { maxWidth = w; } } else { singleDefaults.Add((DateTime)defaultValue.Value); } } dtpFrom.DefaultValues = dtpTo.DefaultValues = singleDefaults; predefRanges.AddRange(DefaultPredefRanges); cmbPredefined.Items.AddRange(predefRanges.ToArray()); cmbPredefined.SelectedIndex = 0; cmbPredefined.Width = maxWidth; UpdateControlFromValue(p.Values as RangePromptValue); ignoreEvents = false; } /// /// Returns the chosen value for this panel. Never null: if null value, will return null wrapped in a SinglePromptValue. /// internal override PromptValue Value { get { UpdateValueFromControl(); RangePromptValue r = new RangePromptValue(PromptData.Type); r.Description = ""; r.IncludeHigh = dateOnly; // bei datetime high nicht includen ( Januar ist z.B. 1.1.2010 00:00 - 1.2.2010 00:00) r.IncludeLow = true; r.OnlyDescription = true; r.StartValue = new SinglePromptValue(currentDate0, null, PromptData.Type); r.EndValue = new SinglePromptValue(currentDate1, null, PromptData.Type); return r; } } /// /// Handles change events of all control in this panel. /// /// the control /// the event args private void HandleChangeEvent(object sender, EventArgs e) { if (ignoreEvents) { return; } ignoreEvents = true; if (sender == cmbMonth) { rbMonth.Checked = true; } else if (sender == cmbQuarter) { rbQuarter.Checked = true; } else if (sender == cmbWeek) { rbWeek.Checked = true; } else if (sender == cmbPredefined) { rbPredefined.Checked = true; } else if (sender == dtpFrom || sender == dtpTo) { rbFreeRange.Checked = true; } UpdateStates(); UpdateValueFromControl(); ValidatePrompt(); OnValueChanged(); ignoreEvents = false; } /// /// updates the various component states (enabled etc.) /// private void UpdateStates() { cmbYear.Enabled = rbMonth.Checked || rbWeek.Checked || rbQuarter.Checked; if (rbMonth.Checked) { cmbYear.Location = new Point(cmbYear.Location.X, cmbMonth.Location.Y); } else if (rbWeek.Checked) { cmbYear.Location = new Point(cmbYear.Location.X, cmbWeek.Location.Y); } else if (rbQuarter.Checked) { cmbYear.Location = new Point(cmbYear.Location.X, cmbQuarter.Location.Y); } } /// internal override bool ValidatePrompt() { errorProvider.Clear(); string errorMsg; bool rangeErr = false; RangePromptValue value = null; try { value = (RangePromptValue)Value; int y = 0; if (cmbYear.Enabled && (!int.TryParse(cmbYear.Text, out y) || y <= dtpFrom.MinDate.Year || y >= dtpFrom.MaxDate.Year) || currentDate0 < dtpFrom.MinDate || currentDate1 >= dtpTo.MaxDate) { errorMsg = strings.Prompt_Error_InvalidYear+ ' ' + (dtpFrom.MinDate.Year + 1) + " - " + (dtpFrom.MaxDate.Year - 1); } else { if (currentDate0 > currentDate1) { errorMsg = strings.Prompt_Error_InvalidRange; } else if (!PromptData.WithinLimits(value)) { errorMsg = strings.Prompt_Error_OutOfRange + PromptData.RangeExplanationMsg; rangeErr = true; } else { return true; } } } catch (Exception exc) { errorMsg = exc.Message; } if (ShowError) { if (rbQuarter.Checked || rbMonth.Checked || rbWeek.Checked) { errorProvider.SetError(cmbYear, errorMsg); } else if (rbPredefined.Checked) { errorProvider.SetError(cmbPredefined, errorMsg); } else if (rangeErr && value != null) { if (!PromptData.WithinLimits(value.StartValue)) { errorProvider.SetError(dtpFrom, errorMsg); } if (!PromptData.WithinLimits(value.EndValue)) { errorProvider.SetError(dtpTo, errorMsg); } return false; } else { errorProvider.SetError(dtpTo, errorMsg); } } ErrorMessage = errorMsg; return false; } /// /// takes the given range and updates all controls /// /// value to update all controls with private void UpdateControlFromValue(RangePromptValue range) { if (range == null) { rbPredefined.Checked = true; UpdateValueFromControl(); return; } Calendar cal = Thread.CurrentThread.CurrentCulture.Calendar; DayOfWeek firstDayOfWeek = Thread.CurrentThread.CurrentCulture.DateTimeFormat.FirstDayOfWeek; DateTime from = (DateTime)range.StartValue.Value; DateTime to = (DateTime)range.EndValue.Value; int fromDayOfMonth = cal.GetDayOfMonth(from); bool fromFirstDayOfWeek = cal.GetDayOfWeek(from) == firstDayOfWeek; int fromWeekOfYear = WeekOfYear(from); int fromMonth = cal.GetMonth(from) - 1; int fromYear = cal.GetYear(from); if (dateOnly) { to = cal.AddDays(to, 1); } int toDayOfMonth = cal.GetDayOfMonth(to); bool toFirstDayOfWeek = cal.GetDayOfWeek(to) == firstDayOfWeek; int toWeekOfYear = WeekOfYear(to); int toMonth = cal.GetMonth(to) - 1; int toYear = cal.GetYear(to); int prerangeIdx = predefRanges.FindIndex(e => from == e.From() && to == e.To()); if (prerangeIdx != -1) { // prerange rbPredefined.Checked = true; cmbPredefined.SelectedIndex = prerangeIdx; } else if (fromDayOfMonth == 1 && toDayOfMonth == 1 && fromMonth + 12 * fromYear + 1 == toMonth + 12 * toYear) { // month rbMonth.Checked = true; cmbMonth.SelectedIndex = fromMonth; cmbYear.Text = fromYear.ToString(); } else if (fromDayOfMonth == 1 && fromMonth % 3 == 0 && fromMonth + 12 * fromYear + 3 == toMonth + 12 * toYear) { // quarter rbQuarter.Checked = true; cmbQuarter.SelectedIndex = fromMonth / 3; cmbYear.Text = fromYear.ToString(); } else if (fromFirstDayOfWeek && toFirstDayOfWeek && fromWeekOfYear + 1 == toWeekOfYear) { // week rbWeek.Checked = true; cmbWeek.SelectedIndex = fromWeekOfYear; cmbYear.Text = fromYear.ToString(); } else { rbFreeRange.Checked = true; } try { dtpFrom.Value = from; dtpTo.Value = dateOnly ? cal.AddDays(to, -1) : to; } catch (ArgumentOutOfRangeException) { //ignore } } /// /// based on the controls in the panel, updates the prompt value /// private void UpdateValueFromControl() { Calendar cal = Thread.CurrentThread.CurrentCulture.Calendar; int year; try { year = int.Parse(cmbYear.Text); } catch (Exception) { //ignored here, checked on validation year = 1900; } if (rbQuarter.Checked) { int quarter = cmbQuarter.SelectedIndex; currentDate0 = CreateDateTime(year, quarter * 3, 1); currentDate1 = CreateDateTime(year, (quarter + 1) * 3, 1); } else if (rbMonth.Checked) { int month = cmbMonth.SelectedIndex; currentDate0 = CreateDateTime(year, month, 1); currentDate1 = CreateDateTime(year, month + 1, 1); } else if (rbWeek.Checked) { int week = cmbWeek.SelectedIndex; currentDate0 = CreateDateTime(year, week); currentDate1 = CreateDateTime(year, week + 1); } else if (rbPredefined.Checked) { PredefRange predefRange = (PredefRange)cmbPredefined.SelectedItem; currentDate0 = predefRange.From(); currentDate1 = predefRange.To(); } else if (rbFreeRange.Checked) { currentDate0 = dtpFrom.Value; currentDate1 = dtpTo.Value; } if (!rbFreeRange.Checked) { if (dateOnly) { currentDate1 = cal.AddDays(currentDate1, -1); } try { dtpFrom.Value = currentDate0; dtpTo.Value = currentDate1; } catch (Exception) { //ignore here, checked during validation } } } /// /// Creates a DateTime with the specified year, month and day. In constrast to the /// DateTime constructor the month and day values can be out of their regular bounds, /// e.g. day 1 or month 13 is accepted here. /// /// the year /// the month, beginning from 0 for january /// the day, beginning from 1 /// the created DateTime private static DateTime CreateDateTime(int year, int month, int day) { var cal = Thread.CurrentThread.CurrentCulture.Calendar; return cal.AddDays(cal.AddMonths(new DateTime(year, 1, 1), month), day - 1); } /// /// Creates a DateTime for the specified week. /// /// the year /// the week, beginning from 0 for the year's first week /// the created DateTime private static DateTime CreateDateTime(int year, int week) { var cul = Thread.CurrentThread.CurrentCulture; var dateTime = new DateTime(year, 1, 1); return cul.Calendar.AddWeeks(dateTime.AddDays(-(dateTime.DayOfWeek - cul.DateTimeFormat.FirstDayOfWeek)), week); } /// /// Computes the week of year according to the current culture. /// /// the DateTime /// the week of year, beginning from 0 for the year's first week private static int WeekOfYear(DateTime date) { return Thread.CurrentThread.CurrentCulture.Calendar.GetWeekOfYear(date, Thread.CurrentThread.CurrentCulture.DateTimeFormat.CalendarWeekRule, Thread.CurrentThread.CurrentCulture.DateTimeFormat.FirstDayOfWeek) - 1; } /// /// Predefined range. /// private interface PredefRange { DateTime From(); DateTime To(); string Name { get; } } /// /// Predefinied custom range. /// private class CustomPredef : PredefRange { private DateTime from, to; private string name; public CustomPredef(string name, DateTime from, DateTime to) { this.from = from; this.to = to; this.name = name; } public DateTime From() { return from; } public DateTime To() { return to; } public string Name { get { return name; } } } /// /// Year to date as predefined range. /// private class YearToDatePredef : PredefRange { public DateTime From() { return new DateTime(DateTime.Now.Year, 1, 1); } public DateTime To() { return CreateDateTime(DateTime.Now.Year, DateTime.Now.Month - 1, DateTime.Now.Day + 1); } public string Name { get { return strings.Prompt_YearToDate; } } } /// /// The current year as predefined range. /// class CurrentYearPredef : PredefRange { public DateTime From() { return new DateTime(DateTime.Now.Year, 1, 1); } public DateTime To() { return new DateTime(DateTime.Now.Year + 1, 1, 1); } public string Name { get { return strings.Prompt_CurrentYear; } } } /// /// The previous year as predefined range. /// class PreviousYearPredef : PredefRange { public DateTime From() { return new DateTime(DateTime.Now.Year - 1, 1, 1); } public DateTime To() { return new DateTime(DateTime.Now.Year, 1, 1); } public string Name { get { return strings.Prompt_PreviousYear; } } } /// /// The current month as predefined range. /// class CurrentMonthPredef : PredefRange { public DateTime From() { return CreateDateTime(DateTime.Now.Year, DateTime.Now.Month - 1, 1); } public DateTime To() { return CreateDateTime(DateTime.Now.Year, DateTime.Now.Month, 1); } public string Name { get { return strings.Prompt_CurrentMonth; } } } /// /// The previous month as predefined range. /// class PrevoiusMonthPredef : PredefRange { public DateTime From() { return CreateDateTime(DateTime.Now.Year, DateTime.Now.Month - 2, 1); } public DateTime To() { return CreateDateTime(DateTime.Now.Year, DateTime.Now.Month - 1, 1); } public string Name { get { return strings.Prompt_PreviousMonth; } } } /// /// The current week as predefined range. /// class CurrentWeekPredef : PredefRange { public DateTime From() { return CreateDateTime(DateTime.Now.Year, WeekOfYear(DateTime.Now)); } public DateTime To() { return CreateDateTime(DateTime.Now.Year, WeekOfYear(DateTime.Now) + 1); } public string Name { get { return strings.Prompt_CurrentWeek; } } } /// /// The previous week as predefined range. /// class PreviousWeekPredef : PredefRange { public DateTime From() { return CreateDateTime(DateTime.Now.Year, WeekOfYear(DateTime.Now) - 1); } public DateTime To() { return CreateDateTime(DateTime.Now.Year, WeekOfYear(DateTime.Now)); } public string Name { get { return strings.Prompt_PreviousWeek; } } } } }