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;
}
}
}
}
}