using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Threading; using Comal.Classes; using InABox.Clients; using InABox.Configuration; using InABox.Core; using InABox.DynamicGrid; using InABox.WPF; using Syncfusion.UI.Xaml.Diagram; using Syncfusion.UI.Xaml.Schedule; using ScheduleType = Syncfusion.UI.Xaml.Schedule.ScheduleType; namespace PRSDesktop { public partial class AssignmentView : UserControl { private class AssignmentViewModel : ScheduleAppointment, IAssignmentViewModel { public Guid AssignmentID { get; set; } public Guid EmployeeID { get; set; } public Brush AppointmentForeground { get; set; } public int Number { get; set; } public string JobNumber { get; set; } public BitmapImage Completed { get; set; } public BitmapImage HasDelivery { get; set; } public BitmapImage Locked { get; set; } public BitmapImage TimeSheet { get; set; } } private class AssignmentFavourite : BaseObject, IAssignmentFavourite { public string Title { get; set; } public Guid JobID { get; set; } public string JobNumber { get; set; } public Guid ITPID { get; set; } public string ITPCode { get; set; } public Guid ActivityID { get; set; } public string ActivityColor { get; set; } public string ActivityName { get; set; } } private int _displayendhour = -1; private int _displaystarthour = -1; private Employee _Employee; private DateTime _startdate = DateTime.Today; private DayOfWeek[] _workdays = { DayOfWeek.Monday, DayOfWeek.Tuesday, DayOfWeek.Wednesday, DayOfWeek.Thursday, DayOfWeek.Friday }; private double _zoom = 100.0F; private readonly BitmapImage back = PRSDesktop.Resources.back.AsBitmapImage(32, 32); private readonly BitmapImage box = PRSDesktop.Resources.box_sml.AsBitmapImage(32, 32); private bool bReady; // Table modeled on EmployeeTeam public CoreTable Employees = new(); private readonly BitmapImage first = PRSDesktop.Resources.first.AsBitmapImage(32, 32); private readonly BitmapImage last = PRSDesktop.Resources.last.AsBitmapImage(32, 32); private LeaveRequestGrid lg; private readonly BitmapImage locked = PRSDesktop.Resources.lock_sml.AsBitmapImage(32, 32); private readonly BitmapImage next = PRSDesktop.Resources.next.AsBitmapImage(32, 32); private Guid SelectedGroup = CoreUtils.FullGuid; private TimesheetGrid tg; private readonly BitmapImage tick = PRSDesktop.Resources.tick_sml.AsBitmapImage(32, 32); private readonly BitmapImage timesheet = PRSDesktop.Resources.clock_sml.AsBitmapImage(32, 32); public AssignmentView() { Assignments = new CoreTable(); ShowTeams = true; ShowDates = true; SettingsTag = ""; CanCreateTimesheets = true; StartDate = DateTime.Today; Employees.LoadColumns(typeof(EmployeeTeam)); Assignments.LoadColumns(typeof(Assignment)); InitializeComponent(); PrevMonth.Content = new Image { Source = first }; PrevDay.Content = new Image { Source = back }; NextDay.Content = new Image { Source = next }; NextMonth.Content = new Image { Source = last }; //DispatcherTimer SelectedEmployeeWatchdog = new DispatcherTimer(); //SelectedEmployeeWatchdog.Interval = new TimeSpan(0, 0, 0, 0, 100); //SelectedEmployeeWatchdog.Tick += SelectedEmployeeWatchdog_Tick; //SelectedEmployeeWatchdog.IsEnabled = true; } public DateTime StartDate { get => _startdate.Date; set { _startdate = value.Date; if (Bookings != null) Bookings.MoveToDate(_startdate); } } public string SettingsTag { get; set; } public bool ShowTeams { get => TeamColumn.Width.Value != 0.0F; set { if (TeamColumn != null) TeamColumn.Width = value ? new GridLength(200, GridUnitType.Pixel) : new GridLength(0, GridUnitType.Pixel); } } public Employee Employee { get => _Employee; set { _Employee = value; ShowDates = value == null; ShowTeams = value == null; SelectedEmployees.Visibility = value == null ? Visibility.Visible : Visibility.Collapsed; } } public bool ShowDates { get => DateRow.Height.IsAuto; set { if (DateRow != null) DateRow.Height = value ? new GridLength(1, GridUnitType.Auto) : new GridLength(0, GridUnitType.Pixel); } } public bool ViewEnabled { get => View.Visibility == Visibility.Visible; set => ViewDock.Visibility = value ? Visibility.Visible : Visibility.Hidden; } public int ViewStyle { get => View.SelectedIndex; set => View.SelectedIndex = value; } public int StartHour { get => (int)StartTime.Value.Value.TotalHours; set { StartTime.Value = new TimeSpan(value, 0, 0); SaveSettings(); } } public int EndHour { get => (int)EndTime.Value.Value.TotalHours; set { EndTime.Value = new TimeSpan(value, 0, 0); SaveSettings(); } } public DayOfWeek[] WorkDays { get => _workdays; set { _workdays = value; UpdateWorkDays(); } } public double Zoom { get => _zoom; set { var bchanged = _zoom != value; _zoom = value; ResizeIntervals(Bookings.ActualHeight); if (bchanged) SaveSettings(); } } public DateTime SelectedDate { get; private set; } public Guid SelectedEmployee { get; private set; } public Brush WorkingHourBrush { get => Bookings.Background; set => Bookings.Background = value; } public Brush NonWorkingHourBrush { get => Bookings.NonWorkingHourBrush; set => Bookings.NonWorkingHourBrush = value; } public Guid SelectedAssignment { get; set; } = Guid.Empty; public bool CanCreateTimesheets { get; set; } public DateTime EndDate { get { if (Bookings.ScheduleType == ScheduleType.Day) return StartDate.AddDays(1); if (Bookings.ScheduleType == ScheduleType.Week) return StartDate.AddDays(7); if (Bookings.ScheduleType == ScheduleType.WorkWeek) return StartDate.AddDays(7); if (Bookings.ScheduleType == ScheduleType.Month) return StartDate.AddMonths(1); return StartDate.AddYears(1); } } public CoreTable Assignments { get; private set; } private void UpdateWorkDays() { var nonworkdays = new List(); for (var day = DayOfWeek.Sunday; day <= DayOfWeek.Saturday; day++) if (!_workdays.Contains(day)) nonworkdays.Add(day.ToString()); Bookings.NonWorkingDays = string.Join(",", nonworkdays); } //public int DisplayEndHour //{ // get { return _displayendhour; } // set // { // _displayendhour = value; // if (!double.IsNaN(ActualHeight)) // ResizeIntervals(ActualHeight); // } //} public void SetDisplayWindow(int start, int end) { _displaystarthour = start; _displayendhour = end; if (!double.IsNaN(ActualHeight)) { ResizeIntervals(ActualHeight); Bookings.MoveToTime(TimeSpan.FromHours(start)); } } public event AssignmentSelectionChangedEvent SelectionChanged; public event AssignmentChangedEvent AssignmentChanged; public event CustomiseAssignments CustomiseAssignments; public event CustomiseAssignmentsContextMenu CustomiseContextMenu; private Assignment FindAssignment(Guid id) { return Assignments.Rows.FirstOrDefault(r => r.Get(c => c.ID).Equals(id))?.ToObject(); } private AssignmentViewModel FindModel(Guid id) { return Bookings.Appointments.FirstOrDefault(x => (x as AssignmentViewModel).AssignmentID.Equals(id)) as AssignmentViewModel; } public void AddAssignment(Assignment assignment) { var row = Assignments.NewRow(); Assignments.LoadRow(row, assignment); Assignments.Rows.Add(row); LoadModel(assignment.ID); } public void GetWindow(TimeSpan time, ref TimeSpan start, ref TimeSpan finish) { var begin = start; var end = finish; foreach (var row in Assignments.Rows) { var curstart = row.Get(x => x.Start); var curfinish = row.Get(x => x.Finish); if (curstart >= time && curstart < end) end = curstart; if (curfinish <= time && curfinish > begin) begin = curfinish; } if (end > begin) { start = begin; finish = end; } } public void Setup() { var settings = new UserConfiguration(SettingsTag).Load(); Employees = new Client().Query( null, new Columns( x => x.TeamLink.ID, x => x.TeamLink.Code, x => x.TeamLink.Name, x => x.EmployeeLink.ID, x => x.EmployeeLink.Name ), new SortOrder(x => x.TeamLink.Code).ThenBy(x => x.EmployeeLink.Name) ); var teams = new Dictionary(); foreach (var row in Employees.Rows) { var teamid = row.Get(c => c.TeamLink.ID); if (!teams.ContainsKey(teamid)) teams[teamid] = row.Get(c => c.TeamLink.Name); } Teams.ItemsSource = teams; View.SelectedIndex = settings.ViewType; StartDate = DateTime.Today; //settings.Date.IsEmpty() ? DateTime.Today : settings.Date.Date; Bookings.MoveToDate(StartDate); if (teams.ContainsKey(settings.GroupID)) { Teams.SelectedValue = settings.GroupID; var emps = new Dictionary(); foreach (var row in Employees.Rows.Where(r => r.Get(c => c.TeamLink.ID).Equals(settings.GroupID) || settings.GroupID.Equals(CoreUtils.FullGuid))) emps[row.Get(c => c.EmployeeLink.ID)] = row.Get(c => c.EmployeeLink.Name); SelectedEmployees.ItemsSource = emps; foreach (var item in SelectedEmployees.Items) { var emp = (KeyValuePair)item; if (settings.SelectedEmployees.Contains(emp.Key)) SelectedEmployees.SelectedItems.Add(item); } } ReloadColumns(); StartTime.Value = new TimeSpan(settings.StartHour, 0, 0); EndTime.Value = new TimeSpan(settings.EndHour, 0, 0); Bookings.AllowDragDrop = false; Bookings.AllowResize = false; bReady = true; } private void Bookings_PreviewKeyUp(object sender, KeyEventArgs e) { } private void SaveSettings() { var settings = new ScheduleSettings(); //settings.Date = StartDate.Date; try { settings.GroupID = Teams.SelectedValue != null ? (Guid)Teams.SelectedValue : Guid.Empty; foreach (var sel in SelectedEmployees.SelectedItems) { var emp = (KeyValuePair)sel; settings.SelectedEmployees.Add(emp.Key); } } catch (Exception e) { Logger.Send(LogType.Error, "", string.Format("*** Unknown Error: {0}\n{1}", e.Message, e.StackTrace)); } settings.StartHour = (int)StartTime.Value.Value.TotalHours; settings.EndHour = (int)EndTime.Value.Value.TotalHours; settings.ViewType = View.SelectedIndex; Task.Run(() => { new UserConfiguration(SettingsTag).Save(settings); }); } private void ConfigureHeader() { // Hide the Date var style = new Style(typeof(ScheduleDaysHeaderViewItemsControl)); style.Setters.Add(new Setter(HeightProperty, Bookings.ScheduleType == ScheduleType.Day ? 0d : 30d)); Resources[typeof(ScheduleDaysHeaderViewItemsControl)] = style; // Show the ResourceNames style = new Style(typeof(DayViewItemHeader)); style.Setters.Add(new Setter(HeightProperty, Bookings.ScheduleType == ScheduleType.Day ? 30d : 0d)); Resources[typeof(DayViewItemHeader)] = style; } private void ResizeIntervals(double height) { if (double.IsNaN(height) || height == 0.0F) return; var start = _displaystarthour != -1 ? _displaystarthour : Bookings.WorkStartHour; var end = _displayendhour != -1 ? _displayendhour : Bookings.WorkEndHour; if (end - start > 0) { var zoomedheight = (height - 40) * (Zoom / 100.0F); double blockcount = (end - start) * 2.0F; Bookings.IntervalHeight = zoomedheight / blockcount; Bookings.WorkStartHour = StartHour; Bookings.WorkEndHour = EndHour; var appts = Bookings.Appointments; Bookings.Appointments = new ScheduleAppointmentCollection(); Bookings.Appointments = null; Bookings.Appointments = appts; } } private void Bookings_SizeChanged(object sender, SizeChangedEventArgs e) { ResizeIntervals(e.NewSize.Height); } private void ReloadColumns() { /* ResourceType resourceType = new ResourceType { TypeName = "Doctor" }; resourceType.ResourceCollection.Add(new Resource { DisplayName = "Dr.Jacob", ResourceName = "Dr.Jacob", }); resourceType.ResourceCollection.Add(new Resource { DisplayName = "Dr.Darsy", ResourceName = "Dr.Darsy" }); schedule.ScheduleResourceTypeCollection = new ObservableCollection { resourceType }; schedule.Resource = "Doctor"; */ ResourceType resources = new ResourceType { TypeName = "Employee" }; List emps = new List(); if (_Employee == null) foreach (var sel in SelectedEmployees.SelectedItems) { var emp = (KeyValuePair)sel; var comps = emp.Value.Split(' '); var display = string.Format("{0} {1}", comps.First(), comps.Length > 1 ? comps.Skip(1).First().Substring(0, 1) : ""); emps.Add(new Resource { DisplayName = display, ResourceName = emp.Key.ToString() }); } else { var resource = new Resource { DisplayName = _Employee.Name, ResourceName = _Employee.ID.ToString() }; emps.Add(resource); } resources.ResourceCollection = new ObservableCollection(emps); Bookings.ScheduleResourceTypeCollection = new ObservableCollection() { resources }; Bookings.Resource = "Employee"; // if (_Employee == null) // foreach (var sel in SelectedEmployees.SelectedItems) // { // var emp = (KeyValuePair)sel; // var comps = emp.Value.Split(' '); // var display = string.Format("{0} {1}", comps.First(), comps.Length > 1 ? comps.Skip(1).First().Substring(0, 1) : ""); // resources.Add(new Resource { DisplayName = display, ResourceName = emp.Key.ToString() }); // } // else // resources.Add(new Resource { DisplayName = _Employee.Name, ResourceName = _Employee.ID.ToString() }); // // foreach (var resource in resources.OrderBy(x => x.DisplayName)) // resources.ResourceCollection.Add(resource); Bookings.ScheduleResourceTypeCollection = new ObservableCollection { resources }; Bookings.DayViewColumnCount = resources.ResourceCollection.Count; } public void Refresh() { CurrentDate.Text = Bookings.ScheduleType == ScheduleType.Day ? string.Format("{0:ddd, dd MMMM yyyy}", StartDate) : string.Format("{0:dd MMM yyyy} - {1:dd MMM yyyy}", StartDate, StartDate.AddDays(7)); var filter = new Filter(x => x.Date).IsGreaterThanOrEqualTo(StartDate).And(x => x.Date).IsLessThan(EndDate); Filter empfilter = null; if (_Employee == null) { empfilter = new Filter(x => x.EmployeeLink.ID).IsEqualTo(CoreUtils.FullGuid); if (Teams.SelectedValue != null) { var teamid = (Guid)Teams.SelectedValue; foreach (var row in Employees.Rows.Where(r => r.Get(c => c.TeamLink.ID).Equals(teamid) || teamid.Equals(CoreUtils.FullGuid))) empfilter = empfilter.Or(x => x.EmployeeLink.ID).IsEqualTo(row.Get(c => c.EmployeeLink.ID)); } } else { empfilter = new Filter(x => x.EmployeeLink.ID).IsEqualTo(_Employee.ID); } filter.Ands.Add(empfilter); Assignments = new Client().Query( filter, new Columns( x => x.ID, x => x.Title, x => x.ActivityLink.ID, x => x.ActivityLink.Color, x => x.ActivityLink.Description, x => x.JobLink.ID, x => x.JobLink.Name, x => x.JobLink.JobNumber, x => x.JobLink.Deleted, x => x.ITP.ID, x => x.ITP.Code, x => x.ITP.Description, x => x.ITP.Deleted, x => x.Number, x => x.Description, x => x.Date, x => x.Start, x => x.Duration, x => x.Finish, x => x.LeaveRequestLink.ID, x => x.LeaveRequestLink.Deleted, x => x.Completed, x => x.Delivery.ID, x => x.Delivery.Notes, x => x.Delivery.Deleted, x => x.TimeSheetLink.ID, x => x.TimeSheetLink.Deleted, x => x.EmployeeLink.ID, x => x.Task.ID, x => x.Task.Number ) ); CustomiseAssignments?.Invoke(this, Assignments); LoadModel(Guid.Empty); } private void LoadModel(Guid id) { AssignmentViewModel selected = null; var appointments = new ScheduleAppointmentCollection(); foreach (var row in Assignments.Rows) { var assignment = row.ToObject(); var sColor = assignment.ActivityLink.Color; var bgColor = string.IsNullOrWhiteSpace(sColor) ? Colors.White : (Color)ColorConverter.ConvertFromString(sColor); var jobdesc = new List(); var itask = assignment.Task.Number; if (itask > 0) jobdesc.Add(string.Format("Task #{0}", itask)); if (assignment.JobLink.IsValid()) { var job = assignment.JobLink.JobNumber; if (assignment.ITP.IsValid()) job = string.Format("{0} {1}", job, assignment.ITP.Code); job = string.Format("({0})", job); jobdesc.Add(job); } var date = assignment.Date; var sNote = assignment.Description + (assignment.Delivery.IsValid() ? "\n" + assignment.Delivery.Notes : ""); var model = new AssignmentViewModel { Subject = string.Format("{0}", assignment.Title?.Trim()), JobNumber = string.Format(" {0} ", string.Join(" ", jobdesc)), Number = assignment.Number, Notes = sNote.Trim(), StartTime = date.Add(assignment.Start), EndTime = date.Add(assignment.Finish), AssignmentID = assignment.ID, EmployeeID = assignment.EmployeeLink.ID, AllDay = false, AppointmentForeground = new SolidColorBrush(Colors.Black), AppointmentBackground = new SolidColorBrush(bgColor), Locked = assignment.LeaveRequestLink.IsValid() ? locked : null, Completed = !assignment.LeaveRequestLink.IsValid() && !assignment.Completed.IsEmpty() ? tick : null, HasDelivery = !assignment.LeaveRequestLink.IsValid() && assignment.Delivery.IsValid() ? box : null, TimeSheet = assignment.TimeSheetLink.IsValid() ? timesheet : null }; model.ResourceCollection = new ObservableCollection() { new Resource() { ResourceName = assignment.EmployeeLink.ID.ToString(), TypeName = "Employee" } }; appointments.Add(model); if (model.AssignmentID == id) selected = model; } Bookings.Appointments = null; Bookings.Appointments = appointments; // if (appointments.Any()) // { // Bookings.MoveToNextAppointment(); // while ((Bookings.SelectedAppointment != null) && (Bookings.SelectedAppointment != selected)) // Bookings.MoveToNextAppointment(); // } ResizeIntervals(Bookings.ActualHeight); } public void UpdateAssignment(Assignment assignment) { var row = Assignments.Rows.FirstOrDefault(r => r.Get(x => x.ID).Equals(assignment.ID)); Assignments.LoadRow(row, assignment); var model = FindModel(assignment.ID); var sColor = assignment.ActivityLink.Color; var bgColor = string.IsNullOrWhiteSpace(sColor) ? Colors.White : (Color)ColorConverter.ConvertFromString(sColor); var date = assignment.Date; var leaveid = assignment.LeaveRequestLink.ID; var job = ""; if (assignment.JobLink.IsValid()) { job = assignment.JobLink.JobNumber; if (assignment.ITP.IsValid()) job = string.Format("{0} {1}", job, assignment.ITP.Code); job = string.Format(" ({0}) ", job); } model.Subject = assignment.Title; model.Number = assignment.Number; model.JobNumber = job; model.Notes = assignment.Description; model.StartTime = date.Add(assignment.Start); model.EndTime = date.Add(assignment.Finish); model.AppointmentBackground = new SolidColorBrush(bgColor); model.Locked = assignment.LeaveRequestLink.IsValid() ? locked : null; model.Completed = !assignment.LeaveRequestLink.IsValid() && !assignment.Completed.IsEmpty() ? tick : null; model.HasDelivery = !assignment.LeaveRequestLink.IsValid() && assignment.Delivery.IsValid() ? box : null; model.TimeSheet = assignment.TimeSheetLink.IsValid() ? timesheet : null; //Bookings.UpdateLayout(); } private void View_SelectionChanged(object sender, SelectionChangedEventArgs e) { StartDate = StartDate.SubtractDays((int)StartDate.DayOfWeek); Bookings.ScheduleType = View.SelectedIndex == 0 ? ScheduleType.Day : ScheduleType.Week; var item = SelectedEmployees.SelectedItems.Count > 0 ? SelectedEmployees.SelectedItems[0] : null; SelectedEmployees.SelectedItems.Clear(); if (View.SelectedIndex == 0) foreach (var i in SelectedEmployees.Items) SelectedEmployees.SelectedItems.Add(i); else SelectedEmployees.SelectedItem = item; ConfigureHeader(); if (bReady) { SaveSettings(); Refresh(); } } private void PrevMonth_Click(object sender, RoutedEventArgs e) { if (Bookings.ScheduleType == ScheduleType.Day) StartDate = StartDate.AddDays(-7); else StartDate = StartDate.AddMonths(-1); Bookings.MoveToDate(StartDate); SelectedDate = StartDate.Add(SelectedDate.TimeOfDay); SelectionChanged?.Invoke(this, null); SaveSettings(); Refresh(); } private void PrevDay_Click(object sender, RoutedEventArgs e) { if (Bookings.ScheduleType == ScheduleType.Day) StartDate = StartDate.AddDays(-1); else StartDate = StartDate.AddDays(-7); Bookings.MoveToDate(StartDate); SelectedDate = StartDate.Add(SelectedDate.TimeOfDay); SelectionChanged?.Invoke(this, null); SaveSettings(); Refresh(); } private void CurrentDate_MouseDoubleClick(object sender, MouseButtonEventArgs e) { StartDate = DateTime.Today; if (Bookings.ScheduleType == ScheduleType.Week) StartDate = StartDate.SubtractDays((int)StartDate.DayOfWeek); Bookings.MoveToDate(StartDate); SelectedDate = StartDate.Add(SelectedDate.TimeOfDay); SelectionChanged?.Invoke(this, null); if (bReady) SaveSettings(); Refresh(); } private void NextDay_Click(object sender, RoutedEventArgs e) { if (Bookings.ScheduleType == ScheduleType.Day) StartDate = StartDate.AddDays(1); else StartDate = StartDate.AddDays(7); Bookings.MoveToDate(StartDate); SelectedDate = StartDate.Add(SelectedDate.TimeOfDay); SelectionChanged?.Invoke(this, null); SaveSettings(); Refresh(); } private void NextMonth_Click(object sender, RoutedEventArgs e) { if (Bookings.ScheduleType == ScheduleType.Day) StartDate = StartDate.AddDays(7); else StartDate = StartDate.AddMonths(1); Bookings.MoveToDate(StartDate); SelectedDate = StartDate.Add(SelectedDate.TimeOfDay); SelectionChanged?.Invoke(this, null); SaveSettings(); Refresh(); } private void Teams_SelectionChanged(object sender, SelectionChangedEventArgs e) { if (!bReady) return; var teamid = (Guid)Teams.SelectedValue; var emps = new Dictionary(); foreach (var row in Employees.Rows.Where(r => r.Get(c => c.TeamLink.ID).Equals(teamid) || teamid.Equals(CoreUtils.FullGuid))) emps[row.Get(c => c.EmployeeLink.ID)] = row.Get(c => c.EmployeeLink.Name); bReady = false; SelectedEmployees.ItemsSource = emps; bReady = true; foreach (var item in SelectedEmployees.Items) SelectedEmployees.SelectedItems.Add(item); } //bool bTicking = false; //private void SelectedEmployeeWatchdog_Tick(object sender, EventArgs e) //{ // if (!bReady || bTicking) // return; // bTicking = true; // if (View.SelectedIndex > 0) // { // if (SelectedEmployees.SelectedItems.Count == 0) // { // if (Bookings.ScheduleResourceTypeCollection[0].ResourceCollection.Count > 0) // { // KeyValuePair? newPair = null; // Resource resource = Bookings.ScheduleResourceTypeCollection[0].ResourceCollection[0] as Resource; // Guid current = Guid.Parse(resource.ResourceName); // foreach (KeyValuePair pair in SelectedEmployees.SelectedItems) // { // if (pair.Key == current) // { // newPair = pair; // break; // } // } // SelectedEmployees.Items.Clear(); // if (newPair.HasValue) // SelectedEmployees.SelectedItems.Add(newPair); // } // } // else // { // KeyValuePair? newGuid = null; // List current = new List(); // foreach (Resource resource in Bookings.ScheduleResourceTypeCollection[0].ResourceCollection) // current.Add(Guid.Parse(resource.ResourceName)); // foreach (KeyValuePair pair in SelectedEmployees.SelectedItems) // { // if (!current.Contains(pair.Key)) // { // newGuid = pair; // break; // } // } // SelectedEmployees.Items.Clear(); // SelectedEmployees.SelectedItems.Add(newGuid); // } // } // bTicking = false; //} private void SelectedEmployees_SelectionChanged(object sender, SelectionChangedEventArgs e) { if (!bReady) return; ReloadColumns(); SaveSettings(); Refresh(); } private void Schedule_AppointmentEditorOpening(object sender, AppointmentEditorOpeningEventArgs e) { if (e.Appointment != null) { var model = (AssignmentViewModel)e.Appointment; var assignment = FindAssignment(model.AssignmentID); if (assignment.LeaveRequestLink.IsValid()) { LeaveRequest leave = null; using (new WaitCursor()) { leave = new Client().Load(new Filter(x => x.ID).IsEqualTo(assignment.LeaveRequestLink.ID)).FirstOrDefault(); } if (leave != null) { if (lg == null) lg = new LeaveRequestGrid(); if (lg.EditItems(new[] { leave })) Refresh(); } else { MessageBox.Show("Cannot Load Leave Request"); } } else { Assignment ass = null; using (new WaitCursor()) { ass = new Client().Load(new Filter(x => x.ID).IsEqualTo(assignment.ID)) .FirstOrDefault(); } if (ass != null) { var ag = new DynamicDataGrid(); if (ag.EditItems(new[] { ass })) Refresh(); } else { MessageBox.Show("Cannot Load Assignment!"); } } } else { var res = e.SelectedResource.FirstOrDefault() as Resource; if (res != null) { var ass = new Assignment(); ass.EmployeeLink.ID = Guid.Parse(res.ResourceName); ass.Date = e.StartTime; ass.Duration = new TimeSpan(1, 0, 0); var ag = new DynamicDataGrid(); if (ag.EditItems(new[] { ass })) Refresh(); } else { MessageBox.Show("No Employee Selected!"); } } e.Cancel = true; } private void Schedule_AppointmentStartDragging(object sender, AppointmentStartDraggingEventArgs e) { var model = e.Appointment as AssignmentViewModel; if (model == null || model.Locked != null || model.TimeSheet != null) e.Cancel = true; } private void Schedule_AppointmentEndDragging(object sender, AppointmentEndDraggingEventArgs e) { var model = (AssignmentViewModel)e.Appointment; var row = model != null ? Assignments.Rows.FirstOrDefault(r => r.Get(x => x.ID).Equals(model.AssignmentID)) : null; if (row != null) { Assignment ass = null; using (new WaitCursor()) { ass = new Client().Load(new Filter(x => x.ID).IsEqualTo(model.AssignmentID)).FirstOrDefault(); } if (ass != null) { var resource = e.Resources.FirstOrDefault() as Resource; var employeeid = Guid.Parse(resource.ResourceName); ass.EmployeeLink.ID = employeeid; var newtime = e.To.TimeOfDay; if (e.To.Minute >= 45) newtime = new TimeSpan(e.To.Hour, 45, 0); else if (e.To.Minute >= 30) newtime = new TimeSpan(e.To.Hour, 30, 0); else if (e.To.Minute >= 15) newtime = new TimeSpan(e.To.Hour, 15, 0); else newtime = new TimeSpan(e.To.Hour, 0, 0); ass.Date = e.To.Date; ass.Start = newtime; using (new WaitCursor()) { new Client().Save(ass, "Dragged by User", (obj, args) => { }); } AssignmentChanged?.Invoke(this, ass); Refresh(); e.Cancel = true; } else { MessageBox.Show("Unable to load Assigmment!"); } } else { MessageBox.Show("Unable to locate Assignment!"); } } private void Schedule_AppointmentEndResizing(object sender, AppointmentEndResizingEventArgs e) { var model = (AssignmentViewModel)e.Appointment; var row = model != null ? Assignments.Rows.FirstOrDefault(r => r.Get(x => x.ID).Equals(model.AssignmentID)) : null; if (row != null) { Assignment ass = null; using (new WaitCursor()) { ass = new Client().Load(new Filter(x => x.ID).IsEqualTo(model.AssignmentID)).FirstOrDefault(); } if (ass != null) { var newtime = e.To; if (e.To.Minute >= 45) newtime = new DateTime(e.To.Year, e.To.Month, e.To.Day, e.To.Hour, 45, 0); else if (e.To.Minute >= 30) newtime = new DateTime(e.To.Year, e.To.Month, e.To.Day, e.To.Hour, 30, 0); else if (e.To.Minute >= 15) newtime = new DateTime(e.To.Year, e.To.Month, e.To.Day, e.To.Hour, 15, 0); else newtime = new DateTime(e.To.Year, e.To.Month, e.To.Day, e.To.Hour, 0, 0); ass.Date = newtime; using (new WaitCursor()) { new Client().Save(ass, "Dragged by User", (obj, args) => { }); } AssignmentChanged?.Invoke(this, ass); Refresh(); e.Cancel = true; } else { MessageBox.Show("Unable to load Assigmment!"); } } else { MessageBox.Show("Unable to locate Assignment!"); } } private TimeSpan GetTime(int row) { var divider = 1; switch (Bookings.TimeInterval) { case TimeInterval.FiveMin: divider = 12; break; case TimeInterval.SixMin: divider = 10; break; case TimeInterval.TenMin: divider = 6; break; case TimeInterval.FifteenMin: divider = 4; break; case TimeInterval.TwentyMin: divider = 3; break; case TimeInterval.ThirtyMin: divider = 2; break; default: divider = 1; break; } var hours = row / divider; var mins = row % divider * (60 / divider); return new TimeSpan(hours, mins, 0); } private TimeSpan GetTime(Point point) { var view = Bookings.FindVisualChildren().FirstOrDefault(x => x.Name.Equals("Scrollviewer1")); var intervalheight = (Bookings.ActualHeight - 30.0F) / ((Bookings.WorkEndHour - Bookings.WorkStartHour) * 4); var row = (int)Math.Truncate((view.VerticalOffset + point.Y - 30.0F) / Bookings.IntervalHeight); var result = GetTime(row); return result; //double intervalheight = (Bookings.ActualHeight - 30.0F) / (double)((Bookings.WorkEndHour - Bookings.WorkStartHour) * 4); //int row = (int)Math.Truncate((point.Y - 30.0F) / intervalheight); //int hour = Bookings.WorkStartHour + (row / 4); //int min = (row % 4) * 15; //return new TimeSpan(hour, min, 0); } private void Bookings_Drop(object sender, DragEventArgs e) { if (e.Data.GetDataPresent("Comal.Classes.Delivery")) { var delivery = (e.Data.GetData("Comal.Classes.Delivery") as CoreRow[]).FirstOrDefault(); if (delivery == null) return; var assignment = new Assignment(); var resource = Bookings.ScheduleResourceTypeCollection[0].ResourceCollection; var colwidth = Bookings.ActualWidth / resource.Count; var column = (int)Math.Truncate(e.GetPosition(Bookings).X / colwidth); var employee = resource[column] as Resource; assignment.EmployeeLink.ID = Guid.Parse(employee.ResourceName); assignment.Date = StartDate; //double intervalheight = (Bookings.ActualHeight - 30.0F) / (double)((Bookings.WorkEndHour - Bookings.WorkStartHour) * 4); //int row = (int)Math.Truncate((e.GetPosition(Bookings).Y - 30.0F) / intervalheight); //int hour = Bookings.WorkStartHour + (row / 4); //int min = (row % 4) * 15; //assignment.Start = new TimeSpan(hour, min, 0); assignment.Start = GetTime(e.GetPosition(Bookings)); assignment.Duration = new TimeSpan(2, 0, 0); assignment.JobLink.ID = delivery.Get(x => x.Job.ID); assignment.Description = string.Format("Delivery Docket #{0}", delivery.Get(x => x.Number)); using (new WaitCursor()) { new Client().Save(assignment, "Created for Delivery"); var del = new Client().Load(new Filter(x => x.ID).IsEqualTo(delivery.Get(x => x.ID))) .FirstOrDefault(); del.Assignment.ID = assignment.ID; new Client().Save(del, "Booked via Scheduler"); } AssignmentChanged?.Invoke(this, assignment); Refresh(); SelectionChanged?.Invoke(this, assignment); } else if (e.Data.GetDataPresent("Comal.Classes.Kanban")) { var kanban = e.Data.GetData("Comal.Classes.Kanban") as Kanban; if (kanban == null) return; var assignment = new Assignment(); var resource = Bookings.ScheduleResourceTypeCollection[0].ResourceCollection; var colwidth = Bookings.ActualWidth / resource.Count; var column = (int)Math.Truncate(e.GetPosition(Bookings).X / colwidth); var employee = resource[column] as Resource; assignment.EmployeeLink.ID = Guid.Parse(employee.ResourceName); assignment.Date = StartDate; var view = Bookings.FindVisualChildren().FirstOrDefault(x => x.Name.Equals("Scrollviewer1")); var intervalheight = (Bookings.ActualHeight - 30.0F) / ((Bookings.WorkEndHour - Bookings.WorkStartHour) * 4); var row = (int)Math.Truncate((view.VerticalOffset + e.GetPosition(Bookings).Y - 30.0F) / Bookings.IntervalHeight); assignment.Start = GetTime(row); assignment.Duration = new TimeSpan(0, 30, 0); assignment.JobLink.ID = kanban.JobLink.ID; assignment.Task.ID = kanban.ID; assignment.Title = kanban.Title; AssignmentChanged?.Invoke(this, assignment); Refresh(); SelectionChanged?.Invoke(this, assignment); } } protected Dictionary EditorValueChanged(object sender, string name, object value) { var editor = (DynamicEditorForm)sender; if (name == "FormLink.ID") { var type = typeof(IDynamicEnclosedListGrid<,>).MakeGenericType(typeof(Kanban), typeof(QAQuestion)); var page = editor.Pages.FirstOrDefault(x => x.GetType().GetInterface(type.Name) != null); if (page != null) { var template = new Client().Load(new Filter(x => x.ID).IsEqualTo(value)).FirstOrDefault(); var load = page.GetType().GetMethod("LoadItems"); //load.Invoke(page, new object[] { template != null ? template.Questions : null }); } } return new Dictionary { { name, value } }; } private void CreateAssignment_Click(object sender, RoutedEventArgs e) { var data = (sender as MenuItem).Tag as AssignmentData; if (data != null) { var ass = new Assignment(); ass.Date = data.Time.Date; ass.Start = data.Time.TimeOfDay; ass.Duration = new TimeSpan(1, 0, 0); ass.EmployeeLink.ID = data.EmployeeID; var ag = new DynamicDataGrid(); ag.OnEditorValueChanged += (s, n, v) => { return EditorValueChanged(s, n, v); }; if (ag.EditItems(new[] { ass })) { AssignmentChanged?.Invoke(this, ass); Refresh(); } } else { MessageBox.Show("Please select an employee first!"); } } private void EditAssignment_Click(object sender, RoutedEventArgs e) { var data = (sender as MenuItem).Tag as AssignmentData; Assignment ass = null; using (new WaitCursor()) { ass = new Client().Load(new Filter(x => x.ID).IsEqualTo(data.Model.AssignmentID)) .FirstOrDefault(); } if (ass != null) { var ag = new DynamicDataGrid(); ag.OnEditorValueChanged += (s, n, v) => { return EditorValueChanged(s, n, v); }; if (ag.EditItems(new[] { ass })) { AssignmentChanged?.Invoke(this, ass); Refresh(); } } else { MessageBox.Show("Cannot Load Assignment!"); } } private void EditLeaveRequest_Click(object sender, RoutedEventArgs e) { var data = Bookings.ContextMenu.Tag as AssignmentData; var ass = FindAssignment(data.Model.AssignmentID); LeaveRequest leave = null; using (new WaitCursor()) { leave = new Client() .Load(new Filter(x => x.ID).IsEqualTo(ass.LeaveRequestLink.ID)).FirstOrDefault(); } if (leave != null) { if (lg == null) lg = new LeaveRequestGrid(); if (lg.EditItems(new[] { leave })) { AssignmentChanged?.Invoke(this, ass); Refresh(); } } else { MessageBox.Show("Cannot Load Leave Request!"); } } private void CreateTimeSheet_Click(object sender, RoutedEventArgs e) { var row = (sender as MenuItem).Tag as CoreRow; var ts = CreateTime(row); if (tg == null) tg = new TimesheetGrid(); if (tg.EditItems(new[] { ts })) { Assignment ass = null; using (new WaitCursor()) { ass = new Client().Load(new Filter(x => x.ID).IsEqualTo(row.Get(x => x.ID))) .FirstOrDefault(); } if (ass != null) { ass.TimeSheetLink.ID = ts.ID; using (new WaitCursor()) { new Client().Save(ass, "Created TimeSheet"); } AssignmentChanged?.Invoke(this, ass); Refresh(); } else { MessageBox.Show("Unable to update Assignment with Timesheet Information"); } } } private static TimeSheet CreateTime(CoreRow row) { var ts = new TimeSheet(); ts.EmployeeLink.ID = row.Get(c => c.EmployeeLink.ID); ts.JobLink.ID = row.Get(c => c.JobLink.ID); ts.ActivityLink.ID = row.Get(c => c.ActivityLink.ID); ts.Date = row.Get(c => c.Date).Date; ts.Start = row.Get(c => c.Start); ts.Finish = row.Get(c => c.Finish); ts.Notes = row.Get(c => c.Description); return ts; } private void EditTimeSheet_Click(object sender, RoutedEventArgs e) { var row = Bookings.ContextMenu.Tag as CoreRow; TimeSheet time = null; using (new WaitCursor()) { time = new Client().Load(new Filter(x => x.ID).IsEqualTo(row.Get(c => c.TimeSheetLink.ID))) .FirstOrDefault(); } if (time == null) time = CreateTime(row); if (tg == null) tg = new TimesheetGrid(); if (tg.EditItems(new[] { time })) { if (row.Get(c => c.TimeSheetLink.ID) != time.ID) { Assignment ass = null; using (new WaitCursor()) { ass = new Client().Load(new Filter(x => x.ID).IsEqualTo(row.Get(x => x.ID))) .FirstOrDefault(); } if (ass != null) { ass.TimeSheetLink.ID = time.ID; using (new WaitCursor()) { new Client().Save(ass, "Updated TimeSheet"); } AssignmentChanged?.Invoke(this, ass); } else { MessageBox.Show("Cannot Locate Assignment for Timesheet"); } } Refresh(); } } private void DeleteTimeSheet_Click(object sender, RoutedEventArgs e) { var row = Bookings.ContextMenu.Tag as CoreRow; var ass = row.ToObject(); var timesheetid = Entity.EntityLinkID(x => x.TimeSheetLink, row) ?? Guid.Empty; if (timesheetid != Guid.Empty) { TimeSheet ts = null; using (new WaitCursor()) { ts = new Client().Load(new Filter(x => x.ID).IsEqualTo(timesheetid)).FirstOrDefault(); } if (ts != null) { using (new WaitCursor()) { new Client().Delete(ts, "TimeSheet Removed From Assignment"); } AssignmentChanged?.Invoke(this, ass); Refresh(); } else { MessageBox.Show("Unable to locate TimeSheet"); } } else { MessageBox.Show("TimeSheet does not exist"); } } private void DeleteAssignment_Click(object sender, RoutedEventArgs e) { var assignmentData = (sender as MenuItem)!.Tag as AssignmentData; if (assignmentData == null) { MessageBox.Show("No Assignment to Delete"); return; } var assignmentID = assignmentData.Model.AssignmentID; if (MessageBox.Show("Are you sure you wish to delete this assignment?", "Confirm Delete", MessageBoxButton.YesNo) == MessageBoxResult.Yes) { Assignment? ass; using (new WaitCursor()) { ass = new Client().Load( new Filter(x => x.ID) .IsEqualTo(assignmentID) ).FirstOrDefault(); } if (ass != null) DeleteBooking(ass); else MessageBox.Show("Unable to locate Assignment!"); } } public void DeleteBooking(Assignment ass) { using (new WaitCursor()) { new Client().Delete(ass, "Assignment Deleted from Scheduler"); } AssignmentChanged?.Invoke(this, ass); Refresh(); } private void DisplayTime_ValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { if (StartTime == null || EndTime == null) return; var start = (int)StartTime.Value.Value.TotalHours; var end = (int)EndTime.Value.Value.TotalHours; if (bReady) SaveSettings(); if (start >= end) return; StartTime.MaxValue = new TimeSpan(end - 1, 0, 0); EndTime.MinValue = new TimeSpan(start + 1, 0, 0); Bookings.WorkStartHour = 24; Bookings.WorkEndHour = 0; var timer = new DispatcherTimer(); timer.Interval = new TimeSpan(100); timer.Tick += (sender, args) => { timer.IsEnabled = false; Bookings.WorkStartHour = start; Bookings.WorkEndHour = end; StartAMPM.Content = Bookings.WorkStartHour < 12 ? " AM " : Bookings.WorkStartHour > 12 ? " PM " : " NN "; EndAMPM.Content = Bookings.WorkEndHour < 12 ? " AM " : Bookings.WorkEndHour > 12 ? " PM " : " NN "; ResizeIntervals(Bookings.ActualHeight); }; timer.IsEnabled = true; } private void ZoomIn_Click(object sender, RoutedEventArgs e) { Zoom *= 1.25F; } private void ZoomOut_Click(object sender, RoutedEventArgs e) { Zoom /= 1.25F; } private void ZoomReset_Click(object sender, RoutedEventArgs e) { Zoom = 100.0F; } private static IAssignmentViewModel FindModel(FrameworkElement element) { if (element == null) return null; if (element.Tag is AssignmentViewModel) return element.Tag as AssignmentViewModel; FrameworkElement parent = VisualTreeHelper.GetParent(element) as FrameworkElement; return FindModel(parent); } private void Bookings_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) { IAssignmentViewModel model = FindModel(e.OriginalSource as FrameworkElement); SelectedEmployee = Guid.Empty; SelectedDate = Bookings.SelectedDate; if (Bookings.ScheduleType == ScheduleType.Day) { var column = (int)(e.GetPosition(Bookings).X / Bookings.ActualWidth * Bookings.DayViewColumnCount); var resource = Bookings.ScheduleResourceTypeCollection[0].ResourceCollection[column] as Resource; SelectedEmployee = Guid.Parse(resource.ResourceName); } if (model != null) { var ass = FindAssignment(model.AssignmentID); if ( ((ass == null) && (SelectedAssignment != null)) || ((ass != null) && (ass.ID != SelectedAssignment)) ) { SelectedAssignment = ass != null ? ass.ID : Guid.Empty; SelectionChanged?.Invoke(this, ass); } } else { if (SelectedAssignment != Guid.Empty) { SelectedAssignment = Guid.Empty; SelectionChanged?.Invoke(this, null); } } e.Handled = true; } private void CreateContextMenu(ContextMenu menu, string name, string header, IAssignmentData args, RoutedEventHandler action, Visibility visibility) { var item = new MenuItem(); item.Name = name; item.Header = header; item.Click += action; item.Visibility = visibility; item.Tag = args; menu.Items.Add(item); } private void Bookings_MouseRightButtonUp(object sender, MouseButtonEventArgs e) { IAssignmentViewModel model = FindModel(e.OriginalSource as FrameworkElement); var time = Bookings.SelectedDate.Date + GetTime(e.GetPosition(Bookings)); var resourcename = ""; if (Bookings.ScheduleType == ScheduleType.Day) { var column = (int)(e.GetPosition(Bookings).X / Bookings.ActualWidth * Bookings.DayViewColumnCount); if (column >= Bookings.ScheduleResourceTypeCollection[0].ResourceCollection.Count) return; var resource = Bookings.ScheduleResourceTypeCollection[0].ResourceCollection[column] as Resource; resourcename = resource.ResourceName; } var args = new AssignmentData(model, Guid.Parse(resourcename), time); var menu = new ContextMenu(); CreateAddMenu(menu, args); CreateEditMenu(menu, args); menu.Items.Add(new Separator { Visibility = Visibility.Collapsed }); if (CreateLeaveMenu(menu,args) || CreateTimeMenu(menu,args)) menu.Items.Add(new Separator()); if (CreateDeleteMenu(menu, args)) menu.Items.Add(new Separator()); CreateZoomMenus(menu, args); CustomiseContextMenu?.Invoke(menu, args); menu.IsOpen = true; e.Handled = true; } public bool CreateAddMenu(ContextMenu menu, IAssignmentData args) { if (args.Model == null) { CreateContextMenu(menu, "CreateAssignment", "Create Assignment", args, CreateAssignment_Click, Visibility.Visible); return true; } return false; } public bool CreateEditMenu(ContextMenu menu, IAssignmentData args) { if (args.Model != null) { CreateContextMenu(menu, "EditAssignment", "Edit Assignment", args, EditAssignment_Click, Visibility.Collapsed); return true; } return false; } public bool CreateLeaveMenu(ContextMenu menu, IAssignmentData args) { if (args.Model == null) return false; var ass = FindAssignment(args.Model.AssignmentID); if (ass == null) return false; if (!ass.LeaveRequestLink.IsValid()) return false; CreateContextMenu(menu, "EditLeaveRequest", "Edit Leave Request", args, EditLeaveRequest_Click, Visibility.Collapsed); return true; } public bool CreateTimeMenu(ContextMenu menu, IAssignmentData args) { if (args.Model == null) return false; var ass = FindAssignment(args.Model.AssignmentID); if (ass == null) return false; if (ass.LeaveRequestLink.IsValid()) return false; if (!ass.TimeSheetLink.IsValid()) return false; CreateContextMenu(menu, "CreateTimeSheet", "Create TimeSheet", args, CreateTimeSheet_Click, Visibility.Collapsed); CreateContextMenu(menu, "EditTimeSheet", "Edit TimeSheet", args, EditTimeSheet_Click, Visibility.Collapsed); CreateContextMenu(menu, "DeleteTimeSheet", "Delete TimeSheet", args, DeleteTimeSheet_Click, Visibility.Collapsed); return true; } public bool CreateDeleteMenu(ContextMenu menu, IAssignmentData args) { if (args.Model != null) { CreateContextMenu(menu, "DeleteAssignment", "Delete Assignment", args, DeleteAssignment_Click, Visibility.Visible); return true; } return false; } public bool CreateZoomMenus(ContextMenu menu, IAssignmentData args) { CreateContextMenu(menu, "ZoomIn", "Zoom In", args, ZoomIn_Click, Visibility.Visible); CreateContextMenu(menu, "ZoomOut", "Zoom Out", args, ZoomOut_Click, Visibility.Visible); CreateContextMenu(menu, "ZoomReset", "Reset Zoom", args, ZoomReset_Click, Visibility.Visible); return true; } private void ShowEmployees_Click(object sender, RoutedEventArgs e) { ShowEmployees.Visibility = Visibility.Collapsed; TeamColumn.Width = new GridLength(200, GridUnitType.Pixel); DateBorder.BorderThickness = new Thickness(0, 0.75, 0, 0.75); } private void HideEmployees_Click(object sender, RoutedEventArgs e) { ShowEmployees.Visibility = Visibility.Visible; TeamColumn.Width = new GridLength(0, GridUnitType.Pixel); DateBorder.BorderThickness = new Thickness(0, 0.75, 0.75, 0.75); } private void Bookings_MouseRightButtonDown(object sender, MouseButtonEventArgs e) { e.Handled = true; } } }