Calendar.xaml.cs 56 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Collections.ObjectModel;
  4. using System.Globalization;
  5. using System.Linq;
  6. using System.Windows;
  7. using System.Windows.Controls;
  8. using System.Windows.Media;
  9. using System.Windows.Threading;
  10. using Comal.Classes;
  11. using InABox.Clients;
  12. using InABox.Configuration;
  13. using InABox.Core;
  14. using InABox.DynamicGrid;
  15. using InABox.WPF;
  16. using Syncfusion.SfSkinManager;
  17. using Syncfusion.UI.Xaml.Scheduler;
  18. using Selection = InABox.Core.Selection;
  19. using SelectionChangedEventArgs = System.Windows.Controls.SelectionChangedEventArgs;
  20. namespace PRSDesktop
  21. {
  22. public partial class Calendar
  23. {
  24. private enum Suppress
  25. {
  26. Selector, // Prevent the Selector from Being Changed
  27. Calendar, // Prevent the Calendar from Being Reconfigured
  28. Events, // Prevent the Selectors from Responding to Events
  29. Refresh, // Stop the Data from Being refreshed
  30. Settings // Dont allow settings to be updated
  31. }
  32. private EventSuppressor suppressor = null;
  33. public void DisableUpdate()
  34. {
  35. if (suppressor == null)
  36. suppressor = new EventSuppressor(Suppress.Refresh, Suppress.Settings);
  37. }
  38. public void EnableUpdate()
  39. {
  40. if (suppressor != null)
  41. {
  42. suppressor.Dispose();
  43. suppressor = null;
  44. }
  45. Refresh();
  46. }
  47. private void DoSetValue<T>(DependencyProperty property, T value, Action? updateselector, Action? updateinterface)
  48. {
  49. SetValue(property, value);
  50. if (!EventSuppressor.IsSet(Suppress.Selector) && (updateselector != null))
  51. using (new EventSuppressor(Suppress.Events))
  52. updateselector();
  53. if (!EventSuppressor.IsSet(Suppress.Calendar) && (updateinterface != null))
  54. updateinterface();
  55. if (!EventSuppressor.IsSet(Suppress.Refresh))
  56. Refresh();
  57. if (!EventSuppressor.IsSet(Suppress.Settings))
  58. {
  59. Properties.SettingsVisible = SettingsVisible;
  60. Properties.Date = SelectedDate;
  61. Properties.StartHour = (int)Bookings.DaysViewSettings.StartHour;
  62. Properties.EndHour = (int)Bookings.DaysViewSettings.EndHour;
  63. Properties.CalendarView = CalendarView;
  64. Properties.EmployeeSelector = EmployeeSettings;
  65. Properties.EmployeeSelection = EmployeeSelection;
  66. Properties.TimeInterval = TimeInterval;
  67. Properties.AssignmentType = AssignmentType;
  68. Properties.BackgroundType = BackgroundType;
  69. Properties.Zoom = Zoom;
  70. SaveSettings?.Invoke(this, Properties);
  71. }
  72. }
  73. #region SettingsVisible Dependency Property
  74. public static readonly DependencyProperty SettingsVisibleProperty =
  75. DependencyProperty.Register(
  76. nameof(SettingsVisible),
  77. typeof(CalendarSettingsVisibility),
  78. typeof(Calendar),
  79. new UIPropertyMetadata(CalendarSettingsVisibility.Hidden)
  80. );
  81. public CalendarSettingsVisibility SettingsVisible
  82. {
  83. get => (CalendarSettingsVisibility)GetValue(SettingsVisibleProperty);
  84. set => SetSettingsVisibility(value);
  85. }
  86. private void SetSettingsVisibility(CalendarSettingsVisibility value)
  87. {
  88. DoSetValue(
  89. SettingsVisibleProperty,
  90. value,
  91. null,
  92. () =>
  93. {
  94. VisibleSettingsColumn.Width = value == CalendarSettingsVisibility.Visible
  95. ? new GridLength(240, GridUnitType.Pixel)
  96. : new GridLength(0, GridUnitType.Pixel);
  97. HiddenSettingsColumn.Width = value == CalendarSettingsVisibility.Hidden
  98. ? new GridLength(35, GridUnitType.Pixel)
  99. : new GridLength(0, GridUnitType.Pixel);
  100. }
  101. );
  102. }
  103. private void HideSideBar_OnClick(object sender, RoutedEventArgs e)
  104. {
  105. if (EventSuppressor.IsSet(Suppress.Events))
  106. return;
  107. using (new EventSuppressor(Suppress.Selector))
  108. SetSettingsVisibility(CalendarSettingsVisibility.Hidden);
  109. }
  110. private void ShowSideBar_OnClick(object sender, RoutedEventArgs e)
  111. {
  112. if (EventSuppressor.IsSet(Suppress.Events))
  113. return;
  114. using (new EventSuppressor(Suppress.Selector))
  115. SetSettingsVisibility(CalendarSettingsVisibility.Visible);
  116. }
  117. #endregion
  118. #region CalendarView Dependency Property
  119. public static readonly DependencyProperty CalendarViewProperty =
  120. DependencyProperty.Register(
  121. nameof(CalendarView),
  122. typeof(CalendarViewType),
  123. typeof(Calendar),
  124. new UIPropertyMetadata(CalendarViewType.Day)
  125. );
  126. public CalendarViewType CalendarView
  127. {
  128. get => (CalendarViewType)GetValue(CalendarViewProperty);
  129. set => SetCalendarView(value);
  130. }
  131. private void SetCalendarView(CalendarViewType value)
  132. {
  133. DoSetValue(
  134. CalendarViewProperty,
  135. value,
  136. () => CalendarViewSelector.SelectedIndex = (int)value,
  137. () =>
  138. {
  139. Bookings.ViewType = value switch
  140. {
  141. CalendarViewType.Day => SchedulerViewType.Day,
  142. CalendarViewType.WorkWeek => SchedulerViewType.WorkWeek,
  143. CalendarViewType.Week => SchedulerViewType.Week
  144. };
  145. ResizeColumns(this.ActualWidth);
  146. }
  147. );
  148. }
  149. private void CalendarViewSelector_SelectionChanged(object sender, SelectionChangedEventArgs e)
  150. {
  151. if (EventSuppressor.IsSet(Suppress.Events))
  152. return;
  153. using (new EventSuppressor(Suppress.Selector))
  154. SetCalendarView((CalendarViewType)CalendarViewSelector.SelectedIndex);
  155. }
  156. #endregion
  157. #region EmployeeSelector Dependency Property
  158. public static readonly DependencyProperty EmployeeSelectionProperty =
  159. DependencyProperty.Register(
  160. nameof(EmployeeSelection),
  161. typeof(EmployeeSelectorData),
  162. typeof(Calendar),
  163. new UIPropertyMetadata(new EmployeeSelectorData())
  164. );
  165. public EmployeeSelectorData EmployeeSelection
  166. {
  167. get => (EmployeeSelectorData)GetValue(EmployeeSelectionProperty);
  168. set => SetEmployeeSelection(value);
  169. }
  170. private void SetEmployeeSelection(EmployeeSelectorData value)
  171. {
  172. DoSetValue(
  173. EmployeeSelectionProperty,
  174. value,
  175. () => EmployeeSelector.Selection = value,
  176. () =>
  177. {
  178. _employees = EmployeeSelector.GetEmployeeData((row) => new EmployeeResourceModel(row));
  179. ReloadColumns();
  180. }
  181. );
  182. }
  183. private void EmployeeSelector_OnSelectionChanged(object sender, EmployeeSelectorSelectionChangedArgs args)
  184. {
  185. if (EventSuppressor.IsSet(Suppress.Events))
  186. return;
  187. using (new EventSuppressor(Suppress.Selector))
  188. SetEmployeeSelection(args.Selection);
  189. }
  190. #endregion
  191. #region EmployeeSettings Dependency Property
  192. public static readonly DependencyProperty EmployeeSettingsProperty =
  193. DependencyProperty.Register(
  194. nameof(EmployeeSettings),
  195. typeof(EmployeeSelectorSettings),
  196. typeof(Calendar),
  197. new UIPropertyMetadata(new EmployeeSelectorSettings())
  198. );
  199. public EmployeeSelectorSettings EmployeeSettings
  200. {
  201. get => (EmployeeSelectorSettings)GetValue(EmployeeSettingsProperty);
  202. set => SetEmployeeSettings(value);
  203. }
  204. private void SetEmployeeSettings(EmployeeSelectorSettings value)
  205. {
  206. DoSetValue(
  207. EmployeeSettingsProperty,
  208. value,
  209. () => EmployeeSelector.Settings = value,
  210. () =>
  211. {
  212. // Nothing to do here
  213. }
  214. );
  215. }
  216. private void EmployeeSelector_OnSettingsChanged(object sender, EmployeeSelectorSettingsChangedArgs args)
  217. {
  218. if (EventSuppressor.IsSet(Suppress.Events))
  219. return;
  220. using (new EventSuppressor(Suppress.Selector))
  221. SetEmployeeSettings(args.Settings);
  222. }
  223. #endregion
  224. #region TimeInterval DependencyProperty
  225. public static readonly DependencyProperty TimeIntervalProperty =
  226. DependencyProperty.Register(
  227. "TimeInterval",
  228. typeof(CalendarTimeInterval),
  229. typeof(Calendar),
  230. new PropertyMetadata(CalendarTimeInterval.FifteenMinutes)
  231. );
  232. public CalendarTimeInterval TimeInterval
  233. {
  234. get => (CalendarTimeInterval)GetValue(TimeIntervalProperty);
  235. set => SetTimeInterval(value);
  236. }
  237. private void SetTimeInterval(CalendarTimeInterval value)
  238. {
  239. DoSetValue(
  240. TimeIntervalProperty,
  241. value,
  242. () => IntervalSelector.SelectedIndex = (int)value,
  243. () =>
  244. {
  245. Bookings.DaysViewSettings.TimeInterval = TimeIntervalToTimeSpan(value);
  246. UpdateZoom();
  247. });
  248. }
  249. private void IntervalSelector_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
  250. {
  251. if (EventSuppressor.IsSet(Suppress.Events))
  252. return;
  253. using (new EventSuppressor(Suppress.Selector))
  254. SetTimeInterval((CalendarTimeInterval)IntervalSelector.SelectedIndex);
  255. }
  256. public TimeSpan TimeIntervalToTimeSpan(CalendarTimeInterval interval)
  257. {
  258. return interval switch
  259. {
  260. CalendarTimeInterval.FiveMinutes => new TimeSpan(0, 5, 0),
  261. CalendarTimeInterval.SixMinutes => new TimeSpan(0, 6, 0),
  262. CalendarTimeInterval.TenMinutes => new TimeSpan(0, 10, 0),
  263. CalendarTimeInterval.FifteenMinutes => new TimeSpan(0, 15, 0),
  264. CalendarTimeInterval.TwentyMinutes => new TimeSpan(0, 20, 0),
  265. CalendarTimeInterval.ThirtyMinutes => new TimeSpan(0, 30, 0),
  266. _ => new TimeSpan(1, 0, 0)
  267. };
  268. }
  269. public int BlocksPerHour(CalendarTimeInterval interval)
  270. {
  271. return interval switch
  272. {
  273. CalendarTimeInterval.FiveMinutes => 12,
  274. CalendarTimeInterval.SixMinutes => 10,
  275. CalendarTimeInterval.TenMinutes => 6,
  276. CalendarTimeInterval.FifteenMinutes => 4,
  277. CalendarTimeInterval.TwentyMinutes => 3,
  278. CalendarTimeInterval.ThirtyMinutes => 2,
  279. _ => 1
  280. };
  281. }
  282. private TimeSpan AdjustStartTime(TimeSpan time)
  283. {
  284. long blocksize = TimeIntervalToTimeSpan(TimeInterval).Ticks;
  285. //long blocksperday = TimeSpan.FromDays(1).Ticks / ;
  286. long blocknumber = time.Ticks / blocksize;
  287. long blockstart = blocknumber * blocksize;
  288. return TimeSpan.FromTicks(blockstart);
  289. }
  290. #endregion
  291. #region SelectedDate Dependency Property
  292. public static readonly DependencyProperty SelectedDateProperty =
  293. DependencyProperty.Register(
  294. nameof(SelectedDate),
  295. typeof(DateTime),
  296. typeof(Calendar),
  297. new UIPropertyMetadata(DateTime.Today)
  298. );
  299. public DateTime SelectedDate
  300. {
  301. get => (DateTime)GetValue(SelectedDateProperty);
  302. set => SetSelectedDate(value);
  303. }
  304. private void SetSelectedDate(DateTime value)
  305. {
  306. DoSetValue(
  307. SelectedDateProperty,
  308. value,
  309. () => DateSelector.Date = value,
  310. () =>
  311. {
  312. Bookings.DisplayDate = value;
  313. Bookings.SelectedDate = value;
  314. }
  315. );
  316. }
  317. private void DateSelector_DateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  318. {
  319. if (EventSuppressor.IsSet(Suppress.Events))
  320. return;
  321. using (new EventSuppressor(Suppress.Selector))
  322. SetSelectedDate(DateSelector.Date);
  323. }
  324. public DateTime StartDate => Properties.CalendarView == CalendarViewType.Day
  325. ? SelectedDate
  326. : SelectedDate.StartOfWeek(DayOfWeek.Monday);
  327. public DateTime EndDate => Properties.CalendarView == CalendarViewType.Day
  328. ? StartDate.AddDays(1)
  329. : Properties.CalendarView == CalendarViewType.WorkWeek
  330. ? StartDate.AddDays(5)
  331. : StartDate.AddDays(7);
  332. #endregion
  333. #region StartHour Dependency Properties
  334. public static readonly DependencyProperty StartHourProperty =
  335. DependencyProperty.Register(
  336. nameof(StartHour),
  337. typeof(int),
  338. typeof(Calendar),
  339. new UIPropertyMetadata(6)
  340. );
  341. public int StartHour
  342. {
  343. get => (int)GetValue(StartHourProperty);
  344. set => SetStartHour(value);
  345. }
  346. private void SetStartHour(int value)
  347. {
  348. value = Math.Min(EndHour-1,Math.Max(0, value));
  349. DoSetValue(
  350. StartHourProperty,
  351. value,
  352. () => StartTimeSelector.Text = FormatHour(value),
  353. () =>
  354. {
  355. Bookings.DaysViewSettings.StartHour = value;
  356. UpdateZoom();
  357. });
  358. }
  359. private void StartTimeSelector_Down_Click(object sender, RoutedEventArgs e)
  360. {
  361. if (EventSuppressor.IsSet(Suppress.Events))
  362. return;
  363. SetStartHour(StartHour - 1);
  364. }
  365. private void StartTimeSelector_Up_Click(object sender, RoutedEventArgs e)
  366. {
  367. if (EventSuppressor.IsSet(Suppress.Events))
  368. return;
  369. SetStartHour(StartHour + 1);
  370. }
  371. #endregion
  372. #region End Hour Property
  373. public static readonly DependencyProperty EndHourProperty =
  374. DependencyProperty.Register(
  375. nameof(EndHour),
  376. typeof(int),
  377. typeof(Calendar),
  378. new UIPropertyMetadata(18)
  379. );
  380. public int EndHour
  381. {
  382. get => (int)GetValue(EndHourProperty);
  383. set => SetEndHour(value);
  384. }
  385. private void SetEndHour(int value)
  386. {
  387. value = Math.Max(StartHour + 1, Math.Min(24, value));
  388. DoSetValue(
  389. EndHourProperty,
  390. value,
  391. () => FinishTimeSelector.Text = FormatHour(value),
  392. () =>
  393. {
  394. Bookings.DaysViewSettings.EndHour = value;
  395. UpdateZoom();
  396. });
  397. }
  398. private void FinishTimeSelector_Down_Click(object sender, RoutedEventArgs e)
  399. {
  400. if (EventSuppressor.IsSet(Suppress.Events))
  401. return;
  402. SetEndHour(EndHour - 1);
  403. }
  404. private void FinishTimeSelector_Up_Click(object sender, RoutedEventArgs e)
  405. {
  406. if (EventSuppressor.IsSet(Suppress.Events))
  407. return;
  408. SetEndHour(EndHour + 1);
  409. }
  410. private string FormatHour(int hour)
  411. {
  412. return hour <= 0 || hour >= 24
  413. ? "Midnight"
  414. : hour < 12
  415. ? string.Format("{0}:00 AM", hour)
  416. : hour > 12
  417. ? string.Format("{0}:00 PM", hour)
  418. : "12:00 NN";
  419. }
  420. #endregion
  421. #region AssignmentType Dependency Property
  422. public static readonly DependencyProperty AssignmentTypeProperty =
  423. DependencyProperty.Register(
  424. nameof(AssignmentType),
  425. typeof(CalendarAssignmentType),
  426. typeof(Calendar),
  427. new UIPropertyMetadata(CalendarAssignmentType.Booked)
  428. );
  429. public CalendarAssignmentType AssignmentType
  430. {
  431. get => (CalendarAssignmentType)GetValue(AssignmentTypeProperty);
  432. set => SetAssignmentType(value);
  433. }
  434. private void SetAssignmentType(CalendarAssignmentType value)
  435. {
  436. DoSetValue(
  437. AssignmentTypeProperty,
  438. value,
  439. () => AssignmentTypeSelector.SelectedIndex = (int)value,
  440. null
  441. );
  442. }
  443. private void AssignmentTypeSelector_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
  444. {
  445. if (EventSuppressor.IsSet(Suppress.Events))
  446. return;
  447. using (new EventSuppressor(Suppress.Selector))
  448. SetAssignmentType((CalendarAssignmentType)AssignmentTypeSelector.SelectedIndex);
  449. }
  450. #endregion
  451. #region BackgroundType Dependency Property
  452. public static readonly DependencyProperty BackgroundTypeProperty =
  453. DependencyProperty.Register(
  454. nameof(BackgroundType),
  455. typeof(CalendarBackgroundType),
  456. typeof(Calendar),
  457. new UIPropertyMetadata(CalendarBackgroundType.Roster)
  458. );
  459. public CalendarBackgroundType BackgroundType
  460. {
  461. get => (CalendarBackgroundType)GetValue(BackgroundTypeProperty);
  462. set => SetBackgroundType(value);
  463. }
  464. private void SetBackgroundType(CalendarBackgroundType type)
  465. {
  466. DoSetValue(
  467. BackgroundTypeProperty,
  468. type,
  469. () => BackgroundTypeSelector.SelectedIndex = (int)type,
  470. null
  471. );
  472. }
  473. private void BackgroundTypeSelector_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
  474. {
  475. if (EventSuppressor.IsSet(Suppress.Events))
  476. return;
  477. using (new EventSuppressor(Suppress.Selector))
  478. SetBackgroundType((CalendarBackgroundType)BackgroundTypeSelector.SelectedIndex);
  479. }
  480. #endregion
  481. #region Zoom Dependency Properties
  482. public static readonly DependencyProperty ZoomProperty =
  483. DependencyProperty.Register(
  484. nameof(Zoom),
  485. typeof(double),
  486. typeof(Calendar),
  487. new UIPropertyMetadata((double)100F)
  488. );
  489. public double Zoom
  490. {
  491. get => (double)GetValue(ZoomProperty);
  492. set => SetZoom(value);
  493. }
  494. private void SetZoom(double value)
  495. {
  496. DoSetValue(
  497. ZoomProperty,
  498. value,
  499. () => ZoomSelector.Text = $"{value:F0}%",
  500. () => UpdateZoom()
  501. );
  502. }
  503. private void UpdateZoom()
  504. {
  505. if (double.IsNaN(this.ActualHeight) || (this.ActualHeight == 0.0F))
  506. return;
  507. var blocksize = (this.ActualHeight - (Bookings.DaysViewSettings.ViewHeaderHeight + Bookings.DaysViewSettings.ResourceHeaderSize + 2.0F)) / ((EndHour - StartHour) * this.BlocksPerHour(TimeInterval));
  508. Bookings.DaysViewSettings.TimeIntervalSize = (double)Zoom * blocksize / 100.0F;
  509. }
  510. private void ZoomSelector_Down_Click(object sender, RoutedEventArgs e)
  511. {
  512. if (EventSuppressor.IsSet(Suppress.Events))
  513. return;
  514. ZoomOut();
  515. }
  516. private void ZoomSelector_Up_Click(object sender, RoutedEventArgs e)
  517. {
  518. if (EventSuppressor.IsSet(Suppress.Events))
  519. return;
  520. ZoomIn();
  521. }
  522. public void ZoomIn() => SetZoom(Zoom * 1.125F);
  523. public void ZoomOut() => SetZoom(Zoom / 1.125F);
  524. public void ResetZoom() => SetZoom(100.0F);
  525. #endregion
  526. #region Event Handlers
  527. public event LoadSettings<CalendarSettings> LoadSettings;
  528. public event SaveSettings<CalendarSettings> SaveSettings;
  529. public CalendarConfigurationEvent ConfigurationChanged;
  530. public event CalendarDataEvent CustomiseContextMenu;
  531. public event CalendarDataEvent SelectionChanged;
  532. public event CalendarDataEvent ItemCreated;
  533. public event CalendarDataEvent ItemChanged;
  534. public event CalendarHandledEvent ItemEditing;
  535. #endregion
  536. public void SelectEmployee(Guid employeeid) => EmployeeSelector.SelectEmployee(employeeid);
  537. // Populated as requiew when EmployeeSelector.SelectionChanged is triggered
  538. private EmployeeResourceModel[] _employees = new EmployeeResourceModel[] { };
  539. // Populated once at startup
  540. private StandardLeaveModel[] _standardleaves = new StandardLeaveModel[] { };
  541. private LeaveRequestModel[] _leaverequests = new LeaveRequestModel[] { };
  542. // Populated on each Refresh
  543. private TimeSheetModel[] _timesheets = new TimeSheetModel[] { };
  544. // Populated on each Refresh
  545. private List<AssignmentModel> _assignments = new List<AssignmentModel>();
  546. private bool bColumnsLoaded;
  547. private AssignmentGrid ag;
  548. public bool IsReady { get; set; }
  549. public CalendarSettings Properties { get; set; }
  550. public Calendar()
  551. {
  552. using (EventSuppressor.All<Suppress>())
  553. {
  554. InitializeComponent();
  555. SetValue(StartHourProperty, 0);
  556. SetValue(EndHourProperty, 24);
  557. // Force the Calendar to display Monday - Sunday
  558. CultureInfo cultureInfo = new CultureInfo(CultureInfo.CurrentCulture.Name);
  559. cultureInfo.DateTimeFormat.FirstDayOfWeek = DayOfWeek.Monday;
  560. DateSelector.Culture = cultureInfo;
  561. SfSkinManager.SetTheme(Bookings, new Theme() { ThemeName = "Office2019White", ScrollBarMode = ScrollBarMode.Compact });
  562. }
  563. }
  564. public virtual void Setup()
  565. {
  566. using (new EventSuppressor(Suppress.Settings, Suppress.Refresh, Suppress.Events))
  567. {
  568. Properties = LoadSettings?.Invoke(this) ?? new CalendarSettings();
  569. SetCalendarView(Properties.CalendarView);
  570. SetSettingsVisibility(Properties.SettingsVisible);
  571. SetSelectedDate(Properties.Date);
  572. SetStartHour(Properties.StartHour);
  573. SetEndHour(Properties.EndHour);
  574. SetTimeInterval(Properties.TimeInterval);
  575. SetAssignmentType(Properties.AssignmentType);
  576. SetBackgroundType(Properties.BackgroundType);
  577. SetCalendarView(Properties.CalendarView);
  578. SetZoom(Properties.Zoom);
  579. EmployeeSelector.Setup();
  580. SetEmployeeSettings(Properties.EmployeeSelector);
  581. SetEmployeeSelection(Properties.EmployeeSelection);
  582. _employees = EmployeeSelector.GetEmployeeData((row) => new EmployeeResourceModel(row));
  583. MultiQuery query = new MultiQuery();
  584. query.Add(
  585. new Filter<LeaveRequest>(x=>x.Status).IsNotEqualTo(LeaveRequestStatus.Rejected),
  586. LeaveRequestModel.Columns
  587. );
  588. query.Add(
  589. null,
  590. StandardLeaveModel.Columns
  591. );
  592. query.Query();
  593. _standardleaves = query.Get<StandardLeave>().Rows.Select(row => new StandardLeaveModel(row)).ToArray();
  594. _leaverequests = query.Get<LeaveRequest>().Rows.Select(row => new LeaveRequestModel(row)).ToArray();
  595. var widthtimer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(100) };
  596. widthtimer.Tick += (o, e) =>
  597. {
  598. if (Bookings.ActualWidth > 0.0F)
  599. {
  600. widthtimer.IsEnabled = false;
  601. ReloadColumns();
  602. }
  603. };
  604. widthtimer.IsEnabled = true;
  605. }
  606. }
  607. public virtual void Shutdown()
  608. {
  609. }
  610. public virtual void Refresh()
  611. {
  612. if (EventSuppressor.IsSet(Suppress.Refresh))
  613. return;
  614. using (new WaitCursor())
  615. {
  616. if (!bColumnsLoaded)
  617. ReloadColumns();
  618. MultiQuery query = new MultiQuery();
  619. var empids = _employees.Select(x => x.ID).ToArray();
  620. if (BackgroundType != CalendarBackgroundType.Roster)
  621. {
  622. query.Add<TimeSheet>(
  623. new Filter<TimeSheet>(x => x.EmployeeLink.ID).InList(empids)
  624. .And(x => x.Date).IsGreaterThanOrEqualTo(StartDate)
  625. .And(x => x.Date).IsLessThanOrEqualTo(EndDate)
  626. .And(x=>x.LeaveRequestLink.ID).IsEqualTo(Guid.Empty)
  627. .And(x=>x.StandardLeaveLink.ID).IsEqualTo(Guid.Empty),
  628. TimeSheetModel.Columns
  629. );
  630. }
  631. query.Add<Assignment>(
  632. new Filter<Assignment>(x => x.EmployeeLink.ID).InList(empids)
  633. .And(x => x.Date).IsGreaterThanOrEqualTo(StartDate)
  634. .And(x => x.Date).IsLessThanOrEqualTo(EndDate),
  635. AssignmentModel.Columns,
  636. new SortOrder<Assignment>(x => x.EmployeeLink.ID).ThenBy(x => x.Date).ThenBy(x => x.Booked.Duration, SortDirection.Descending)
  637. );
  638. query.Query();
  639. _timesheets = (BackgroundType == CalendarBackgroundType.Roster)
  640. ? new TimeSheetModel[] { }
  641. : query.Get<TimeSheet>().Rows.Select(r => new TimeSheetModel(r)).ToArray();
  642. _assignments = query.Get<Assignment>().Rows.Select(r => new AssignmentModel(r)).ToList();
  643. LoadBackground();
  644. var appointments = new CalendarAppointments();
  645. LoadStandardLeaves(appointments);
  646. LoadLeaveRequests(appointments);
  647. LoadAssignments(appointments);
  648. try
  649. {
  650. Bookings.DisplayDate = Bookings.SelectedDate.HasValue ? Bookings.SelectedDate.Value : StartDate;
  651. Bookings.ItemsSource = appointments;
  652. }
  653. catch (Exception e)
  654. {
  655. Logger.Send(LogType.Error, "", string.Format("*** Unknown Error: {0}\n{1}", e.Message, e.StackTrace));
  656. }
  657. }
  658. }
  659. public EmployeeRosterItem GetRoster(Guid employeeid, DateTime date)
  660. {
  661. var employee = _employees.FirstOrDefault(x => x.ID == employeeid);
  662. var roster = RosterUtils.GetRoster(employee?.Roster, employee?.Start, date);
  663. return roster;
  664. }
  665. public bool GetActiveWindow(Guid employeeid, DateTime date, ref TimeSpan start, ref TimeSpan finish)
  666. {
  667. bool result = false;
  668. foreach (var assignment in _assignments.Where(a => (a.EmployeeID == employeeid) && (a.Date) == date))
  669. {
  670. result = true;
  671. var curstart = AssignmentType switch
  672. {
  673. CalendarAssignmentType.Booked => assignment.BookedStart,
  674. CalendarAssignmentType.Actual => assignment.ActualStart,
  675. _ => Assignment.EffectiveTime(assignment.ActualStart, assignment.BookedStart)
  676. };
  677. var curfinish = AssignmentType switch
  678. {
  679. CalendarAssignmentType.Booked => assignment.BookedFinish,
  680. CalendarAssignmentType.Actual => assignment.ActualFinish,
  681. _ => Assignment.EffectiveTime(
  682. assignment.ActualFinish,
  683. Assignment.EffectiveTime(assignment.ActualStart, assignment.BookedStart)
  684. .Add(assignment.BookedDuration)
  685. )
  686. };
  687. start = start > curstart ? curstart : start;
  688. finish = finish < curfinish ? curfinish : finish;
  689. }
  690. if ((BackgroundType == CalendarBackgroundType.Roster) ||
  691. ((BackgroundType == CalendarBackgroundType.Automatic) && (date >= DateTime.Today)))
  692. {
  693. var employee = _employees.FirstOrDefault(x => x.ID == employeeid);
  694. if (employee != null)
  695. {
  696. var roster = RosterUtils.GetRoster(employee.Roster, employee.Start, date);
  697. if (roster != null)
  698. {
  699. var blocks = roster.GetBlocks(date, TimeSpan.MinValue, TimeSpan.MaxValue);
  700. foreach (var block in blocks)
  701. {
  702. start = start > block.Start ? block.Start : start;
  703. finish = finish < block.Finish ? block.Finish : finish;
  704. }
  705. }
  706. }
  707. }
  708. else
  709. {
  710. foreach (var timesheet in _timesheets.Where(t => (t.EmployeeID == employeeid) && (t.Date == date)))
  711. {
  712. result = true;
  713. var curstart = !timesheet.Approved.IsEmpty()
  714. ? timesheet.ApprovedStart
  715. : timesheet.Start;
  716. var curfinish = !timesheet.Approved.IsEmpty()
  717. ? timesheet.ApprovedFinish
  718. : timesheet.Finish;
  719. start = start > curstart ? curstart : start;
  720. finish = finish < curfinish ? curfinish : finish;
  721. }
  722. }
  723. return result;
  724. }
  725. public CoreRow[] GetAssignments(Guid employeeid, DateTime date)
  726. {
  727. return _assignments.Where(a => (a.Row != null) && (a.EmployeeID == employeeid) && (a.Date == date)).Select(x => x.Row!).ToArray();
  728. }
  729. public void UpdateAssignment(Assignment assignment)
  730. {
  731. if (Bookings.ItemsSource is CalendarAppointments appointments)
  732. {
  733. var appointment = appointments.FirstOrDefault(x => (Guid)x.Id == assignment.ID) as AssignmentAppointment;
  734. if (appointment != null)
  735. {
  736. appointments.Remove(appointment);
  737. _assignments.Remove(appointment.Model);
  738. }
  739. var table = new CoreTable();
  740. table.LoadColumns(typeof(Assignment));
  741. var row = table.NewRow();
  742. table.LoadRow(row, assignment);
  743. var model = new AssignmentModel(row);
  744. _assignments.Add(model);
  745. LoadAssignment(model, appointments);
  746. }
  747. }
  748. private void LoadBackground()
  749. {
  750. var regions = new ObservableCollection<SpecialTimeRegion>();
  751. foreach (var resource in Bookings.ResourceCollection)
  752. {
  753. var sEmpID = ((SchedulerResource)resource).Id as string;
  754. var empid = Guid.Parse(sEmpID);
  755. var employee = _employees.FirstOrDefault(x => x.ID == empid);
  756. for (var date = StartDate; date < EndDate; date = date.AddDays(1))
  757. {
  758. if ((BackgroundType == CalendarBackgroundType.Roster) ||
  759. ((BackgroundType == CalendarBackgroundType.Automatic) && (date >= DateTime.Today)))
  760. {
  761. var roster = RosterUtils.GetRoster(employee?.Roster, employee?.Start, date);
  762. if (roster != null)
  763. {
  764. var blocks = roster.GetBlocks(date, TimeSpan.FromSeconds(0), TimeSpan.FromDays(1));
  765. foreach (var block in blocks)
  766. {
  767. regions.Add(
  768. new SpecialTimeRegion
  769. {
  770. StartTime = date.Add(block.Start),
  771. EndTime = date.Add(block.Finish.Subtract(TimeSpan.FromSeconds(1))),
  772. ResourceIdCollection = new ObservableCollection<object> { ((SchedulerResource)resource).Id },
  773. Background = new SolidColorBrush(Colors.Yellow) {Opacity = 0.3},
  774. Foreground = new SolidColorBrush(Colors.Black),
  775. Text = ""
  776. }
  777. );
  778. }
  779. }
  780. }
  781. else
  782. {
  783. foreach (var timesheet in _timesheets.Where(t => (t.EmployeeID == empid) && (t.Date == date)))
  784. {
  785. var start = !timesheet.Approved.IsEmpty()
  786. ? timesheet.ApprovedStart
  787. : timesheet.Start;
  788. var finish = !timesheet.Approved.IsEmpty()
  789. ? timesheet.ApprovedFinish
  790. : timesheet.Finish;
  791. regions.Add(
  792. new SpecialTimeRegion
  793. {
  794. StartTime = date.Add(start),
  795. EndTime = date.Add(finish),
  796. ResourceIdCollection = new ObservableCollection<object> { ((SchedulerResource)resource).Id },
  797. Background = new SolidColorBrush(!timesheet.Approved.IsEmpty() ? Colors.LightGreen : Colors.LightSalmon) { Opacity = 0.4 },
  798. Foreground = new SolidColorBrush(Colors.Transparent),
  799. Text = "",
  800. CanMergeAdjacentRegions = false
  801. }
  802. );
  803. }
  804. }
  805. }
  806. }
  807. Bookings.DaysViewSettings.SpecialTimeRegions = regions;
  808. }
  809. private void LoadStandardLeaves(CalendarAppointments appointments)
  810. {
  811. for (var date = StartDate; date < EndDate; date = date.AddDays(1))
  812. {
  813. var leaves = _standardleaves.Where(x =>
  814. (x.From <= date)
  815. && (x.To.Add(x.ToTime) > date)
  816. ).ToArray();
  817. foreach (var leave in leaves)
  818. {
  819. foreach (var resource in Bookings.ResourceCollection)
  820. {
  821. var sEmpID = ((SchedulerResource)resource).Id as string;
  822. var empid = Guid.Parse(sEmpID);
  823. var employee = _employees.FirstOrDefault(x => x.ID == empid);
  824. var start = (date.Date == leave.From.Date) ? leave.FromTime : TimeSpan.FromSeconds(0);
  825. var finish = (date.Date == leave.To.Date) ? leave.ToTime : TimeSpan.FromDays(1).Subtract(TimeSpan.FromSeconds(1));
  826. var roster = RosterUtils.GetRoster(employee?.Roster, employee?.Start, date);
  827. if (roster != null)
  828. {
  829. var blocks = roster.GetBlocks(date, start, finish);
  830. foreach (var block in blocks)
  831. {
  832. var appt = new StandardLeaveAppointment(leave, _ => empid, x => x.Color, block);
  833. appointments.Add(appt);
  834. }
  835. }
  836. }
  837. }
  838. }
  839. }
  840. private void LoadLeaveRequests(CalendarAppointments appointments)
  841. {
  842. for (var date = StartDate; date < EndDate; date = date.AddDays(1))
  843. {
  844. var ids = Bookings.ResourceCollection
  845. .Cast<SchedulerResource>()
  846. .Where(x=>!String.IsNullOrWhiteSpace(x.Id as String))
  847. .Select(x => Guid.Parse(x.Id.ToString() ?? ""));
  848. var leaves = _leaverequests.Where(x =>
  849. (x.From <= date)
  850. && (x.To.Add(x.ToTime) > date)
  851. && ids.Contains(x.EmployeeID)
  852. ).ToArray();
  853. foreach (var leave in leaves)
  854. {
  855. var employee = _employees.FirstOrDefault(x => x.ID == leave.EmployeeID);
  856. var roster = RosterUtils.GetRoster(employee?.Roster, employee?.Start, date);
  857. if (roster != null)
  858. {
  859. var start = (date.Date == leave.From.Date) ? leave.FromTime : TimeSpan.FromSeconds(0);
  860. var finish = (date.Date == leave.To.Date) ? leave.ToTime : TimeSpan.FromDays(1).Subtract(TimeSpan.FromSeconds(1));
  861. var blocks = roster.GetBlocks(date, start, finish);
  862. foreach (var block in blocks)
  863. {
  864. var appt = new LeaveRequestAppointment(leave, x=>x.EmployeeID, x => x.Color, block);
  865. appointments.Add(appt);
  866. }
  867. }
  868. }
  869. }
  870. }
  871. private void LoadAssignment(AssignmentModel assignment, CalendarAppointments appointments)
  872. {
  873. var model = new AssignmentAppointment(assignment, x => x.EmployeeID, x => x.Color, AssignmentType);
  874. appointments.Add(model);
  875. }
  876. private void LoadAssignments(CalendarAppointments appointments)
  877. {
  878. foreach (var assignment in _assignments)
  879. LoadAssignment(assignment, appointments);
  880. }
  881. public DataModel DataModel(Selection selection)
  882. {
  883. var ids = _assignments.Select(x => x.ID).ToArray();
  884. return new AutoDataModel<Assignment>(new Filter<Assignment>(x => x.ID).InList(ids));
  885. }
  886. // private void ResizeIntervals(double height)
  887. // {
  888. // if (Bookings.FindVisualChildren<ScrollPanel>().Any())
  889. // {
  890. //
  891. // if (height > 95 && Bookings.DaysViewSettings.EndHour - Bookings.DaysViewSettings.StartHour > 0)
  892. // {
  893. // double scrollheight = _employees.Length * 75 > Bookings.ActualWidth ? 15.0F : 0.0F;
  894. // var header = _employees.Length > 1 ? 93.0F + scrollheight : 50.0F;
  895. // Bookings.DaysViewSettings.TimeIntervalSize =
  896. // (height - header) / ((Bookings.DaysViewSettings.EndHour - Bookings.DaysViewSettings.StartHour) * 2.0F);
  897. // }
  898. // }
  899. //
  900. // // var scrollers = Bookings.FindVisualChildren<ScrollViewer>().Where(x => string.Equals(x.Name, "PART_TimeSlotScrollViewer")).ToArray();
  901. // // foreach (var scroll in scrollers)
  902. // // scroll.VerticalScrollBarVisibility = ScrollBarVisibility.Hidden;
  903. //
  904. // }
  905. private void Schedule_SizeChanged(object sender, SizeChangedEventArgs e)
  906. {
  907. //ResizeIntervals(e.NewSize.Height);
  908. ResizeColumns(e.NewSize.Width);
  909. }
  910. private void ResizeColumns(double width)
  911. {
  912. if (double.IsNaN(width) || !Bookings.FindVisualChildren<ScrollPanel>().Any())
  913. return;
  914. var maxcount = (int)width / 75;
  915. Bookings.DaysViewSettings.VisibleResourceCount = Math.Min(maxcount,
  916. _employees.Length * (Bookings.ViewType == SchedulerViewType.Day ? 1 : Bookings.ViewType == SchedulerViewType.WorkWeek ? 5 : 7));
  917. if (Bookings.ResourceCollection is ObservableCollection<SchedulerResource> resources)
  918. {
  919. var colwidth = GetResourceColumnWidth();
  920. foreach (var emp in _employees)
  921. {
  922. var resource = resources.FirstOrDefault(x => String.Equals(x.Id?.ToString(), emp.ID.ToString()));
  923. if (resource != null)
  924. {
  925. var comps = emp.Name.Split(' ');
  926. var display = emp.Name;
  927. if (colwidth < 75)
  928. display = string.Format("{0}{1}", comps[0].Length > 0 ? comps[0][..1] : "",
  929. comps.Length > 1 ? comps.Skip(1).First()[..1].ToUpper() : "");
  930. else if (colwidth < 150)
  931. display = string.Format("{0} {1}", comps.First(),
  932. comps.Length > 1 ? comps.Skip(1).First()[..1].ToUpper() : "");
  933. resource.Name = display;
  934. }
  935. }
  936. }
  937. }
  938. private T CheckGrid<T>(ref T grid) where T : new()
  939. {
  940. if (grid == null)
  941. grid = new T();
  942. return grid;
  943. }
  944. private void ReloadColumns()
  945. {
  946. ResizeColumns(Bookings.ActualWidth);
  947. var colwidth = GetResourceColumnWidth();
  948. var resources = new List<SchedulerResource>();
  949. foreach (var emp in _employees)
  950. {
  951. var comps = emp.Name.Split(' ');
  952. var display = emp.Name;
  953. if (colwidth < 75)
  954. display = CoreUtils.Codify(emp.Name);
  955. else if (colwidth < 150)
  956. display = string.Format("{0} {1}", comps.Length > 0 ? comps.First() : "", comps.Length > 1 ? comps.Skip(1).First().Substring(0, 1).ToUpper() : "");
  957. resources.Add(new SchedulerResource { Name = display, Id = emp.ID.ToString() });
  958. }
  959. var sorted = new ObservableCollection<SchedulerResource>();
  960. foreach (var resource in resources.OrderBy(x => x.Name))
  961. sorted.Add(resource);
  962. try
  963. {
  964. Bookings.DaysViewSettings.ResourceHeaderSize = sorted.Count <= 1 ? 0 : 45;
  965. }
  966. catch (Exception e)
  967. {
  968. Logger.Send(LogType.Error, "", string.Format("*** Unknown Error: {0}\n{1}", e.Message, e.StackTrace));
  969. }
  970. //ResizeIntervals(Bookings.ActualHeight);
  971. try
  972. {
  973. Bookings.ResourceCollection = sorted;
  974. }
  975. catch (Exception e)
  976. {
  977. Logger.Send(LogType.Error, "", string.Format("*** Unknown Error: {0}\n{1}", e.Message, e.StackTrace));
  978. }
  979. bColumnsLoaded = true;
  980. }
  981. // private SchedulerResource GetCurrentResource()
  982. // {
  983. // var p = Mouse.GetPosition(Bookings);
  984. // var panels = Bookings.FindVisualChildren<ScrollViewer>().FirstOrDefault(x => string.Equals(x.Name, "PART_ViewHeaderScrollViewer"));
  985. // var resource = (int)((p.X + panels.HorizontalOffset - (Bookings.DaysViewSettings.TimeRulerSize + 20F)) / GetResourceColumnWidth());
  986. // return (Bookings.ResourceCollection as Collection<SchedulerResource>)[resource];
  987. // }
  988. //
  989. // private DateTime GetCurrentTime()
  990. // {
  991. // var p = Mouse.GetPosition(Bookings);
  992. // var hours = (p.Y - (_employees.Length > 1 ? 95.0F : 50.0F)) / (Bookings.DaysViewSettings.TimeIntervalSize * 2F) +
  993. // Bookings.DaysViewSettings.StartHour;
  994. // var result = Bookings.SelectedDate.Value + TimeSpan.FromHours(hours);
  995. // return result;
  996. // }
  997. private double GetResourceColumnWidth()
  998. {
  999. var colcount = Math.Max(1, _employees.Length);
  1000. colcount = colcount * (Bookings.ViewType == SchedulerViewType.Day ? 1 : Bookings.ViewType == SchedulerViewType.Day ? 5 : 7);
  1001. var colwidth = Bookings.ActualWidth / colcount;
  1002. var minwidth = (Bookings.ActualWidth - (Bookings.DaysViewSettings.TimeRulerSize + 20F)) / Bookings.DaysViewSettings.VisibleResourceCount;
  1003. return Math.Max(minwidth, colwidth);
  1004. }
  1005. private void Schedule_AppointmentEditorOpening(object sender, AppointmentEditorOpeningEventArgs e)
  1006. {
  1007. e.Cancel = true;
  1008. }
  1009. private Dictionary<CalendarMenuName, MenuItem> _menuitems = new Dictionary<CalendarMenuName, MenuItem>();
  1010. public MenuItem? FindMenu(CalendarMenuName name)
  1011. {
  1012. _menuitems.TryGetValue(name, out MenuItem result);
  1013. return result;
  1014. }
  1015. private void Bookings_OnSchedulerContextMenuOpening(object? sender, SchedulerContextMenuOpeningEventArgs e)
  1016. {
  1017. MenuItem CreateMenu<T>(ItemsControl menu, CalendarMenuName name, string header, Action<T?>? action = null, T? data = null) where T : class
  1018. {
  1019. var item = new MenuItem();
  1020. item.Name = name.ToString();
  1021. item.Header = header;
  1022. if (action != null)
  1023. item.Click += (o,args) => action(data);
  1024. item.IsEnabled = data != null;
  1025. menu.Items.Add(item);
  1026. _menuitems[name] = item;
  1027. return item;
  1028. }
  1029. e.ContextMenu.Items.Clear();
  1030. if (e.MenuType == SchedulerContextMenuType.Appointment)
  1031. {
  1032. var appointment = e.MenuInfo.Appointment as AssignmentAppointment;
  1033. if (appointment == null)
  1034. {
  1035. MessageBox.Show("Cannot edit this entry!");
  1036. return;
  1037. }
  1038. CreateMenu(e.ContextMenu, CalendarMenuName.Edit, "Edit Assignment", EditAssignment, appointment.Model);
  1039. e.ContextMenu.Items.Add(new Separator());
  1040. CreateMenu(e.ContextMenu, CalendarMenuName.Copy, "Copy Assignment", CopyAssignment, appointment.Model);
  1041. e.ContextMenu.Items.Add(new Separator());
  1042. CreateMenu(e.ContextMenu, CalendarMenuName.Fill, "Fill Available Time", FillAssignment, appointment.Model);
  1043. e.ContextMenu.Items.Add(new Separator());
  1044. var digitalForms = new MenuItem { Header = "Digital Forms" };
  1045. DynamicGridUtils.PopulateFormMenu<AssignmentForm, Assignment, AssignmentLink>(
  1046. digitalForms,
  1047. appointment.Model.ID,
  1048. () => new Client<Assignment>().Load(new Filter<Assignment>(x => x.ID).IsEqualTo(appointment.Model.ID)).First(),
  1049. false);
  1050. e.ContextMenu.Items.Add(digitalForms);
  1051. e.ContextMenu.Items.Add(new Separator());
  1052. CreateMenu(e.ContextMenu, CalendarMenuName.Delete, "Delete Assignment", DeleteAssignment, appointment.Model);
  1053. e.ContextMenu.Items.Add(new Separator());
  1054. CreateMenu<object>(e.ContextMenu, CalendarMenuName.ZoomIn, "Zoom In", (data) => ZoomIn(), appointment.Model);
  1055. CreateMenu<object>(e.ContextMenu, CalendarMenuName.ZoomOut, "Zoom Out", (data) => ZoomOut(), appointment.Model);
  1056. CreateMenu<object>(e.ContextMenu, CalendarMenuName.ResetZoom, "Reset Zoom", (data) => ResetZoom(), appointment.Model);
  1057. CustomiseContextMenu?.Invoke(e.ContextMenu, new CalendarDataDataEventArgs<AssignmentModel>(appointment.Model));
  1058. }
  1059. else if (e.MenuType == SchedulerContextMenuType.TimeSlotCell)
  1060. {
  1061. if (Guid.TryParse(e.MenuInfo.Resource.Id?.ToString(), out Guid employeeid))
  1062. {
  1063. var slot = new CalendarTimeSlot(employeeid, e.MenuInfo.DateTime.Value);
  1064. CreateMenu(e.ContextMenu, CalendarMenuName.CreateNew, "New Assignment", (data) => CreateAssignment(slot), slot);
  1065. if (_copiedmodel != null)
  1066. {
  1067. e.ContextMenu.Items.Add(new Separator());
  1068. CreateMenu(e.ContextMenu, CalendarMenuName.Paste, "Paste Assignment", (data) => PasteAssignment(slot), slot);
  1069. }
  1070. e.ContextMenu.Items.Add(new Separator());
  1071. CreateMenu<object>(e.ContextMenu, CalendarMenuName.ZoomIn, "Zoom In", (data) => ZoomIn(), slot);
  1072. CreateMenu<object>(e.ContextMenu, CalendarMenuName.ZoomOut, "Zoom Out", (data) => ZoomOut(), slot);
  1073. CreateMenu<object>(e.ContextMenu, CalendarMenuName.ResetZoom, "Reset Zoom", (data) => ResetZoom(), slot);
  1074. CustomiseContextMenu?.Invoke(e.ContextMenu, new CalendarDataDataEventArgs<CalendarTimeSlot>(slot));
  1075. }
  1076. }
  1077. //CreateMenu(menu, "ZoomIn", "Zoom In", args, ZoomIn_Click, Visibility.Visible);
  1078. //CreateMenu(menu, "ZoomOut", "Zoom Out", args, ZoomOut_Click, Visibility.Visible);
  1079. //CreateMenu(menu, "ZoomReset", "Reset Zoom", args, ZoomReset_Click, Visibility.Visible);
  1080. }
  1081. public Assignment CreateAssignment(CalendarTimeSlot slot)
  1082. {
  1083. if (slot == null)
  1084. {
  1085. MessageBox.Show("Please select an employee first!");
  1086. return null;
  1087. }
  1088. var ass = new Assignment();
  1089. ass.Date = slot.Time.Date;
  1090. ass.Booked.Start = AdjustStartTime(slot.Time.TimeOfDay);
  1091. ass.Booked.Duration = TimeIntervalToTimeSpan(TimeInterval);
  1092. ass.Booked.Finish = ass.Booked.Start + ass.Booked.Duration;
  1093. if ((AssignmentType == CalendarAssignmentType.Actual) || ((AssignmentType == CalendarAssignmentType.Automatic) && (ass.Date <= DateTime.Today)))
  1094. {
  1095. ass.Actual.Start = ass.Booked.Start;
  1096. ass.Actual.Duration = ass.Booked.Duration;
  1097. ass.Actual.Finish = ass.Actual.Start + ass.Actual.Duration;
  1098. }
  1099. ass.EmployeeLink.ID = slot.EmployeeID;
  1100. ItemCreated?.Invoke(this, new CalendarDataDataEventArgs<Assignment>(ass));
  1101. var args = new CalendarHandledEventArgs<Assignment>(ass);
  1102. ItemEditing?.Invoke(this, args);
  1103. if (args.Status == CalendarHandledStatus.Cancel)
  1104. return null;
  1105. if ((args.Status == CalendarHandledStatus.Handled) || CheckGrid(ref ag).EditItems(new[] { ass }))
  1106. {
  1107. UpdateAssignment(ass);
  1108. _copiedmodel = null;
  1109. }
  1110. return ass;
  1111. }
  1112. private void FillAssignment(AssignmentModel model)
  1113. {
  1114. MessageBox.Show("Not Yet Implemented");
  1115. }
  1116. private void EditAssignment(AssignmentModel model)
  1117. {
  1118. if (model == null)
  1119. {
  1120. MessageBox.Show("Please select an entry first!");
  1121. return;
  1122. }
  1123. var grid = CheckGrid(ref ag);
  1124. var ass = new Client<Assignment>().Query(new Filter<Assignment>(x => x.ID).IsEqualTo(model.ID), grid.LoadEditorColumns())
  1125. .ToObjects<Assignment>().FirstOrDefault();
  1126. if (grid.EditItems(new[] { ass }))
  1127. {
  1128. ItemChanged?.Invoke(this, new CalendarDataDataEventArgs<Assignment>(ass));
  1129. Refresh();
  1130. }
  1131. }
  1132. private void DeleteAssignment(AssignmentModel model)
  1133. {
  1134. if (model == null)
  1135. {
  1136. MessageBox.Show("Please select an entry first!");
  1137. return;
  1138. }
  1139. if (MessageBox.Show("Are you sure you wish to delete this assignment?", "Confirm Delete", MessageBoxButton.YesNo) != MessageBoxResult.Yes)
  1140. return;
  1141. var ass = new Assignment { ID = model.ID };
  1142. new Client<Assignment>().Delete(ass, "Assignment Deleted from Scheduler");
  1143. ItemChanged?.Invoke(this, new CalendarDataDataEventArgs<Assignment>(ass));
  1144. Refresh();
  1145. SelectionChanged?.Invoke(this, new CalendarDataDataEventArgs<Assignment>(null));
  1146. }
  1147. private AssignmentModel _copiedmodel;
  1148. private void CopyAssignment(AssignmentModel model)
  1149. {
  1150. if (model == null)
  1151. {
  1152. MessageBox.Show("Please select an entry first!");
  1153. return;
  1154. }
  1155. _copiedmodel = model;
  1156. }
  1157. private Assignment PasteAssignment(CalendarTimeSlot slot)
  1158. {
  1159. if (slot == null)
  1160. {
  1161. MessageBox.Show("Please select an employee first!");
  1162. return null;
  1163. }
  1164. var ass = _assignments.FirstOrDefault(a => a.ID == _copiedmodel.ID)?.Row?.ToObject<Assignment>();
  1165. if (ass == null)
  1166. {
  1167. MessageBox.Show("Cannot find copied entry!");
  1168. return null;
  1169. }
  1170. ass.Date = SelectedDate.Date;
  1171. ass.ID = Guid.Empty;
  1172. ass.Number = 0;
  1173. ass.CommitChanges();
  1174. ass.Booked.Start = AdjustStartTime(slot.Time.TimeOfDay);
  1175. ass.Booked.Duration = TimeIntervalToTimeSpan(TimeInterval);
  1176. ass.Booked.Finish = ass.Booked.Start + ass.Booked.Duration;
  1177. if ((AssignmentType == CalendarAssignmentType.Actual) || ((AssignmentType == CalendarAssignmentType.Automatic) && (ass.Date <= DateTime.Today)))
  1178. {
  1179. ass.Actual.Start = ass.Booked.Start;
  1180. ass.Actual.Duration = ass.Booked.Duration;
  1181. ass.Actual.Finish = ass.Actual.Start + ass.Actual.Duration;
  1182. }
  1183. ass.EmployeeLink.ID = slot.EmployeeID;
  1184. new Client<Assignment>().Save(ass, "");
  1185. UpdateAssignment(ass);
  1186. _copiedmodel = null;
  1187. return ass;
  1188. }
  1189. private void Bookings_OnAppointmentTapped(object? sender, AppointmentTappedArgs e)
  1190. {
  1191. //if (e.Appointment is AssignmentModel model)
  1192. if (e.Appointment is AssignmentAppointment appointment)
  1193. {
  1194. ICalendarDataEventArgs args = new CalendarDataDataEventArgs<Assignment>(
  1195. appointment.Model.Row?.ToObject<Assignment>()
  1196. );
  1197. SelectionChanged?.Invoke(this, args);
  1198. }
  1199. else
  1200. SelectionChanged?.Invoke(this, new CalendarDataDataEventArgs<Assignment>(null));
  1201. }
  1202. private void Calendar_OnSizeChanged(object sender, SizeChangedEventArgs e)
  1203. {
  1204. if (double.IsNaN(this.ActualHeight) || (this.ActualHeight == 0))
  1205. return;
  1206. UpdateZoom();
  1207. }
  1208. }
  1209. }