using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using Comal.Classes;
using InABox.Clients;
using InABox.Core;
using InABox.DynamicGrid;
using InABox.WPF;
using Syncfusion.Windows.Controls.Gantt;
using Syncfusion.Windows.Controls.Grid;
using GridSelectionMode = Syncfusion.Windows.Controls.Grid.GridSelectionMode;
namespace PRSDesktop
{
///
/// Interaction logic for TaskPlannerControl.xaml
///
public partial class TaskPlannerControl : UserControl, ITaskControl
{
private enum Suppress
{
This
}
private CoreTable _kanbans;
private CoreTable _relationships;
private readonly ObservableCollection _resources = new();
private CoreTable _stages;
private readonly ObservableCollection _tasks = new();
private bool bLoading;
public TaskPlannerControl()
{
using (new EventSuppressor(Suppress.This))
{
InitializeComponent();
Gantt.ItemsSource = _tasks;
Gantt.ResourceCollection = _resources;
}
}
public void Setup()
{
LoadKanbanTypes();
}
private void LoadKanbanTypes()
{
using (new EventSuppressor(Suppress.This))
{
var types = new Dictionary
{
{ CoreUtils.FullGuid, "All Task Types" },
{ Guid.Empty, "Uncategorized Tasks" }
};
new Client().Query(new Filter(x => x.Hidden).IsEqualTo(false))
.IntoDictionary(types, x => x.ID, x => x.Description);
SelectedType.ItemsSource = types;
}
}
public void Refresh(bool resetselection)
{
Refresh();
}
public void Shutdown()
{
}
private void Gantt_TemplateApplied(object sender, TemplateAppliedEventArgs args)
{
if (Gantt.GanttGrid != null)
{
Gantt.GanttGrid.Model.Options.ListBoxSelectionMode = GridSelectionMode.One;
Gantt.GanttGrid.Model.Sizer.AllowAutoCalculateSize = true;
Gantt.GanttGrid.Model.Sizer.ListenToSizeChanged = true;
Gantt.GanttGrid.Model.Options.ColumnSizer = GridControlLengthUnitType.Star;
Gantt.GanttGrid.RowHeaderWidth = 0;
Gantt.GanttGrid.ShowRowHeader = false;
CreateGanttColumns();
//Gantt.GanttGrid.ReadOnly = true;
}
}
private void CreateGanttColumns()
{
if (Gantt.GanttGrid == null)
return;
Gantt.GanttGrid.Columns.Clear();
//Gantt.GanttGrid.Columns.Add(new Syncfusion.Windows.Controls.Grid.GridTreeColumn("TaskId") { Width = 60F, HeaderText = "#", StyleInfo = new Syncfusion.Windows.Controls.Grid.GridStyleInfo() { VerticalAlignment = VerticalAlignment.Center, HorizontalAlignment = HorizontalAlignment.Center } });
Gantt.GanttGrid.Columns.Add(new GridTreeColumn("TaskName")
{
Width = 220F, PercentWidth = 100F, HeaderText = "Description",
StyleInfo = new GridStyleInfo { VerticalAlignment = VerticalAlignment.Center }
});
Gantt.GanttGrid.Columns.Add(new GridTreeColumn("StartDate")
{
Width = 70F, HeaderText = "Start",
StyleInfo = new GridStyleInfo
{ VerticalAlignment = VerticalAlignment.Center, Format = "dd MMM yy", HorizontalAlignment = HorizontalAlignment.Center }
});
Gantt.GanttGrid.Columns.Add(new GridTreeColumn("Manpower")
{
Width = 60F, HeaderText = "Hrs",
StyleInfo = new GridStyleInfo { VerticalAlignment = VerticalAlignment.Center, HorizontalAlignment = HorizontalAlignment.Center }
});
Gantt.GanttGrid.Columns.Add(new GridTreeColumn("Percentage")
{
Width = 40F, HeaderText = "%",
StyleInfo = new GridStyleInfo
{ VerticalAlignment = VerticalAlignment.Center, Format = "#0.##%", HorizontalAlignment = HorizontalAlignment.Center }
});
Gantt.GanttGrid.Columns.Add(new GridTreeColumn("FinishDate")
{
Width = 70F, HeaderText = "Due",
StyleInfo = new GridStyleInfo
{ VerticalAlignment = VerticalAlignment.Center, Format = "dd MMM yy", HorizontalAlignment = HorizontalAlignment.Center }
});
}
private void LoadData()
{
var query = new MultiQuery();
query.Add(
new QueryDef(
new Filter(x => x.Closed).IsEqualTo(DateTime.MinValue).And(x => x.JobLink.ID).IsEqualTo(Host.ParentID),
new Columns
(
x => x.ID,
x => x.Created,
x => x.DueDate,
x => x.Completed,
x => x.Description,
x => x.Summary,
x => x.Category,
x => x.EmployeeLink.ID,
x => x.EmployeeLink.Name,
x => x.ManagerLink.ID,
x => x.Title,
x => x.Notes,
x => x.Number,
x => x.Attachments,
x => x.Type.Code,
x => x.StartDate,
x => x.EstimatedTime,
x => x.ActualTime,
x => x.Type.ID
),
new SortOrder(x => x.DueDate).ThenBy(x => x.StartDate)
),
typeof(Kanban)
);
query.Add(
new QueryDef(
new Filter(x => x.Job.ID).IsEqualTo(Host.ParentID),
null,
null
),
typeof(JobStage)
);
query.Add(
new QueryDef(
new Filter(x => x.Parent.ID).IsEqualTo(Host.ParentID),
new Columns(
x => x.ID,
x => x.Predecessor.ID,
x => x.Successor.ID,
x => x.Type,
x => x.Parent.ID
),
null
),
typeof(KanbanRelationship)
);
query.Query();
_kanbans = query.Get(typeof(Kanban));
_stages = query.Get(typeof(JobStage));
_relationships = query.Get(typeof(KanbanRelationship));
}
public void Refresh()
{
bLoading = true;
using (new WaitCursor())
{
try
{
LoadData();
_tasks.Clear();
var startmarker = new GanttTask
{
StartDate = DateTime.Today,
FinishDate = DateTime.Today,
TaskName = "Start of Job",
IsMileStone = true
};
var endmarker = new GanttTask
{
StartDate = DateTime.Today,
FinishDate = DateTime.Today,
TaskName = "End of Job",
IsMileStone = true
};
var curstart = DateTime.MaxValue;
var curend = DateTime.MinValue;
_tasks.Add(startmarker);
foreach (var row in _kanbans.Rows)
if ((Host.KanbanSettings.PlannerSettings.IncludeCompleted || row.Get(c => c.Completed).IsEmpty()) &&
(Host.KanbanSettings.PlannerSettings.SelectedType == CoreUtils.FullGuid ||
row.Get(c => c.Type.ID) == Host.KanbanSettings.PlannerSettings.SelectedType))
{
var task = new GanttTask();
LoadTask(row, task);
if (task.StartDate < curstart)
curstart = task.StartDate;
if (task.FinishDate > curend)
curend = task.FinishDate;
_tasks.Add(task);
}
_tasks.Add(endmarker);
foreach (var row in _relationships.Rows)
{
var predtask = _tasks.FirstOrDefault(x => x.ID == row.Get(c => c.Predecessor.ID));
var succtask = _tasks.FirstOrDefault(x => x.ID == row.Get(c => c.Successor.ID));
if (predtask != null && succtask != null)
{
var type = row.Get(x => x.Type);
var relationship = type == GanttRelationshipType.FinishToFinish
? GanttTaskRelationship.FinishToFinish
: type == GanttRelationshipType.FinishToStart
? GanttTaskRelationship.FinishToStart
: type == GanttRelationshipType.StartToFinish
? GanttTaskRelationship.StartToFinish
: GanttTaskRelationship.StartToStart;
succtask.Predecessor.Add(new Predecessor { GanttTaskIndex = predtask.TaskId, GanttTaskRelationship = relationship });
}
}
var _striplines = new List();
foreach (var row in _stages.Rows)
{
if (!_striplines.Any())
{
var startline = new StripLineInfo();
startline.Content = "Start of Job";
startline.StartDate = row.Get(c => c.StartDate);
startline.EndDate = startline.StartDate;
startline.HorizontalContentAlignment = HorizontalAlignment.Center;
startline.VerticalContentAlignment = VerticalAlignment.Center;
startline.Background = Brushes.Gold;
startline.RepeatBehavior = Repeat.None;
_striplines.Add(startline);
}
var stripline = new StripLineInfo();
stripline.Content = row.Get(c => c.Name);
stripline.StartDate = row.Get(c => c.EndDate);
stripline.EndDate = stripline.StartDate;
stripline.HorizontalContentAlignment = HorizontalAlignment.Center;
stripline.VerticalContentAlignment = VerticalAlignment.Center;
stripline.Background = Brushes.Gold;
stripline.RepeatBehavior = Repeat.None;
_striplines.Add(stripline);
if (stripline.StartDate < curstart)
curstart = stripline.StartDate;
if (stripline.EndDate > curend)
curend = stripline.EndDate;
}
Gantt.StripLines = _striplines;
Gantt.ShowStripLines = true;
Gantt.UseOnDemandSchedule = true;
if (curstart != DateTime.MaxValue)
{
startmarker.StartDate = curstart.Date;
startmarker.FinishDate = curstart.Date;
}
if (curend != DateTime.MinValue)
{
endmarker.StartDate = curend.Date.AddDays(1);
endmarker.FinishDate = curend.AddDays(1);
}
}
finally
{
bLoading = false;
}
foreach (var task in _tasks)
task.PropertyChanged += Task_PropertyChanged;
}
}
private void LoadTask(CoreRow row, GanttTask task)
{
var start = row.Get(x => x.StartDate);
if (start.IsEmpty())
start = row.Get(x => x.Created);
var estimated = row.Get(x => x.EstimatedTime);
if (estimated.TotalMilliseconds == 0L)
estimated = TimeSpan.FromHours(1);
var actual = row.Get(x => x.ActualTime);
var progress = estimated.TotalMilliseconds != 0L ? actual.TotalMilliseconds * 100L / estimated.TotalMilliseconds : 0F;
task.TaskId = row.Get(c => c.Number);
task.ID = row.Get(x => x.ID);
task.TaskName = string.Format("{0} - {1}", row.Get(c => c.Number), row.Get(x => x.Title));
task.StartDate = start.Date;
task.FinishDate = row.Get(x => x.DueDate).Date.AddDays(1).AddMilliseconds(-1);
task.Manpower = estimated;
task.Percentage = progress;
task.IsMileStone = false;
var empid = row.EntityLinkID(x => x.EmployeeLink) ?? Guid.Empty;
if (empid != Guid.Empty)
{
var resource = _resources.FirstOrDefault(x => (x as GanttResource).Guid == empid) as GanttResource;
if (resource == null)
{
resource = new GanttResource
{
ID = _resources.Count,
Guid = empid,
Name = row.Get(c => c.EmployeeLink.Name)
};
_resources.Add(resource);
}
task.Resources = new ObservableCollection { resource };
}
}
private void Task_PropertyChanged(object sender, PropertyChangedEventArgs args)
{
if (bLoading)
return;
if (!string.Equals(args.PropertyName, "StartDate") && !string.Equals(args.PropertyName, "FinishDate"))
return;
var row = _kanbans.Rows.FirstOrDefault(r => r.Get(x => x.ID) == ((GanttTask)sender).ID);
var kanban = row?.ToObject();
var task = sender as GanttTask;
var bChanged = false;
if (task != null && kanban != null)
{
if (string.Equals(args.PropertyName, "FinishDate"))
{
kanban.DueDate = task.FinishDate.Date;
bChanged = true;
}
else if (string.Equals(args.PropertyName, "StartDate"))
{
kanban.StartDate = task.StartDate.Date;
bChanged = true;
}
}
if (bChanged)
{
row.Set(x => x.DueDate, kanban.DueDate.Date);
row.Set(x => x.StartDate, kanban.StartDate.Date);
new Client().Save(kanban, "Updated by Planner", (o, e) => { });
}
}
private void Gantt_RelationshipEstablished(object sender, GanttRelationshipEstablishedEventArgs args)
{
var pred = args.StartTask as GanttTask;
var succ = args.EndTask as GanttTask;
if (pred == null || pred.IsMileStone)
throw new Exception("Cannot make a connection here");
if (succ == null || succ.IsMileStone)
throw new Exception("Cannot make a connection here");
var relationship = new KanbanRelationship();
relationship.Parent.ID = Host.ParentID;
relationship.Predecessor.ID = pred.ID;
relationship.Successor.ID = succ.ID;
relationship.Type = args.Relationship == GanttTaskRelationship.FinishToFinish
? GanttRelationshipType.FinishToFinish
: args.Relationship == GanttTaskRelationship.FinishToStart
? GanttRelationshipType.FinishToStart
: args.Relationship == GanttTaskRelationship.StartToFinish
? GanttRelationshipType.StartToFinish
: GanttRelationshipType.StartToStart;
new Client().Save(relationship, "", (o, e) =>
{
var row = _relationships.NewRow();
_relationships.LoadRow(row, relationship);
_relationships.Rows.Add(row);
});
}
private void GanttContextMenu_Opened(object sender, RoutedEventArgs e)
{
var task = Gantt.SelectedItems.FirstOrDefault() as GanttTask;
UnlinkTaskMenu.IsEnabled = task != null && task.Predecessor.Any();
UnlinkTaskMenu.Tag = task;
}
private void UnlinkTaskMenu_Click(object sender, RoutedEventArgs args)
{
var successor = (sender as MenuItem).Tag as GanttTask;
if (successor == null)
return;
var deletes = new List();
foreach (var link in successor.Predecessor)
{
var predecessor = _tasks.FirstOrDefault(x => x.TaskId == link.GanttTaskIndex);
if (predecessor != null)
{
var rows = _relationships.Rows.Where(r =>
r.Get(c => c.Successor.ID).Equals(successor.ID) &&
r.Get(c => c.Predecessor.ID).Equals(predecessor.ID)).ToArray();
foreach (var row in rows)
{
deletes.Add(row.ToObject());
_relationships.Rows.Remove(row);
}
}
}
if (deletes.Any())
new Client().Delete(deletes, "", (o, e) => { });
successor.Predecessor.Clear();
}
private void EditTask_Click(object sender, RoutedEventArgs e)
{
DoEditTask();
}
private void DoEditTask()
{
var task = Gantt.SelectedItems.FirstOrDefault() as GanttTask;
if (task == null)
return;
var row = _kanbans.Rows.FirstOrDefault(r => r.Get(x => x.ID) == task.ID);
var kanban = row?.ToObject();
if (kanban != null)
{
var bOK = new KanbanGrid().EditItems(new[] { kanban });
if (bOK)
{
_kanbans.LoadRow(row, kanban);
LoadTask(row, task);
}
}
}
private void AddTask_Click(object sender, RoutedEventArgs e)
{
var kanban = new Kanban();
kanban.JobLink.ID = Host.ParentID;
var bOK = new KanbanGrid().EditItems(new[] { kanban });
if (bOK)
{
var row = _kanbans.NewRow();
_kanbans.LoadRow(row, kanban);
var task = new GanttTask();
LoadTask(row, task);
_tasks.Add(task);
task.PropertyChanged += Task_PropertyChanged;
}
}
private void SelectedType_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (EventSuppressor.IsSet(Suppress.This))
{
Host.KanbanSettings.PlannerSettings.SelectedType = SelectedType.SelectedValue == null ? Guid.Empty : (Guid)SelectedType.SelectedValue;
Host.SaveSettings();
Refresh();
}
}
private void IncludeCompleted_Checked(object sender, RoutedEventArgs e)
{
Host.KanbanSettings.PlannerSettings.IncludeCompleted = IncludeCompleted.IsChecked == true;
Host.SaveSettings();
Refresh();
}
#region ITaskControl Support
public KanbanViewType KanbanViewType => KanbanViewType.Planner;
public ITaskHost Host { get; set; }
public bool IsReady { get; set; }
public string SectionName => "Task Planner";
public DataModel DataModel(Selection selection)
{
return new AutoDataModel(new Filter(x => x.ID).IsEqualTo(Guid.Empty));
}
public IEnumerable SelectedModels(TaskModel sender = null)
{
MessageBox.Show("TaskPlannerControl.SelectedModels() is not Implemented!");
return new TaskModel[] { };
}
#endregion
private void TaskTypeButton_OnClick(object sender, RoutedEventArgs e)
{
var list = new MasterList(typeof(KanbanType));
list.ShowDialog();
LoadKanbanTypes();
}
}
}