calendarGrid: Removed MouseEnter event and added it to CGView which now has to handle it properly.

CGAppointments: now supports cloning.
CGDocument: Added RefreshDocumentAsync, which retrives data from the server w/o asking the grid to refersh.
CGDocumentManager: CGView.InitializeDocView does not take appointments as argument; callers are changed.
CGView: Many Changes:
 - Opening a Schedule nows calls up a splash and a wait cursor while loading.
 - Events coming from the server are now handled asynchronously (not on UI thread). This results in much better responsiveness.
 - Appointments, Availabilities, Resources are all set in the CalendarGrid by UpdateArrays; as a centralized point of drawing the grid.
 - A mistaken "feature"--stealing focus from each others windows, was removed--CalendarGrid.Focus event only fired now if the form is the Active Form. This is accomplished using GetActiveWindow() from user32.dll (a Win32 API).
LoadingSplash: Opacity removed; form resized.
This commit is contained in:
sam 2011-01-20 14:32:28 +00:00
parent 5cf703c69c
commit 3a03dc6871
7 changed files with 200 additions and 91 deletions

View File

@ -7,7 +7,7 @@
/// by Sam Habiel for WorldVista. The original source code is lost.
/// </summary>
[Serializable]
public class CGAppointments : IEnumerable
public class CGAppointments : IEnumerable, ICloneable
{
private Hashtable apptList = new Hashtable();
@ -55,6 +55,16 @@
return this.apptList;
}
}
//smh test
//one problem: Hashtable is a shallow copy.
//so it shouldn't work. But let's see.
public object Clone()
{
CGAppointments appts = new CGAppointments();
appts.apptList = (Hashtable)apptList.Clone();
return appts;
}
}
}

View File

@ -269,7 +269,31 @@ namespace IndianHealthService.ClinicalScheduling
return this.WeekNeedsRefresh(1, m_dSelectedDate, out this.m_dStartDate, out this.m_dEndDate);
}
//sam: This is a test that duplicates RefreshDocument, but without the UpdateAllViews,
// as that has to be done synchornously.
//XXXXXX: Needs to be refactored obviously, but now for testing.
public void RefreshDocumentAsync()
{
bool bRet = false;
if (m_sResourcesArray.Count == 0)
return;
if (m_sResourcesArray.Count == 1)
{
bRet = this.WeekNeedsRefresh(1, m_dSelectedDate, out this.m_dStartDate, out this.m_dEndDate);
}
else
{
this.m_dStartDate = m_dSelectedDate;
this.m_dEndDate = m_dSelectedDate;
this.m_dEndDate = this.m_dEndDate.AddHours(23);
this.m_dEndDate = this.m_dEndDate.AddMinutes(59);
this.m_dEndDate = this.m_dEndDate.AddSeconds(59);
}
bRet = RefreshSchedule();
}
public void RefreshDocument()
{
bool bRet = false;
@ -289,6 +313,7 @@ namespace IndianHealthService.ClinicalScheduling
}
bRet = RefreshSchedule();
this.UpdateAllViews();
}
@ -343,7 +368,6 @@ namespace IndianHealthService.ClinicalScheduling
view.InitializeDocView(this,
this.DocManager,
m_dStartDate,
this.Appointments,
this.DocName);
view.Show();

View File

@ -206,7 +206,7 @@ namespace IndianHealthService.ClinicalScheduling
//Create new View
//A view is a specific arrangement of appointments and availabilites that constitute a document
CGView view = new CGView();
view.InitializeDocView(doc, _current, doc.StartDate, doc.Appointments, _current.WindowText);
view.InitializeDocView(doc, _current, doc.StartDate, _current.WindowText);
//Handle BMX Event
Application.DoEvents();
@ -1067,7 +1067,7 @@ namespace IndianHealthService.ClinicalScheduling
doc.DocManager = _current;
CGView view = new CGView();
view.InitializeDocView(doc, _current, doc.StartDate, doc.Appointments, _current.WindowText);
view.InitializeDocView(doc, _current, doc.StartDate, _current.WindowText);
view.Show();
view.Activate();
@ -1116,7 +1116,7 @@ namespace IndianHealthService.ClinicalScheduling
doc.DocManager = _current;
CGView view = new CGView();
view.InitializeDocView(doc, _current, doc.StartDate, doc.Appointments, _current.WindowText);
view.InitializeDocView(doc, _current, doc.StartDate, _current.WindowText);
view.Show();
view.Activate();

View File

@ -7,7 +7,7 @@ using System.Diagnostics;
using System.Data;
using System.Threading;
using IndianHealthService.BMXNet;
using System.Runtime.InteropServices;
namespace IndianHealthService.ClinicalScheduling
{
@ -127,15 +127,20 @@ namespace IndianHealthService.ClinicalScheduling
public void InitializeDocView(CGDocument doc,
CGDocumentManager docMgr,
DateTime dStartDate,
CGAppointments cgAppts,
string sText)
{
System.IntPtr pHandle = this.Handle;
this.DocManager = docMgr;
this.StartDate = dStartDate;
this.Document = doc;
this.Appointments = cgAppts;
//Rather strangely, this line is needed for God knows Why...
//Without it, the Grid tries to draw appointments, but can't.
//Making a constructor in the Calendar Grid itself didn't work. Don't know why.
//XXX: For later investigation.
this.Appointments = new CGAppointments();
// Set username and division up top
this.Text = this.DocManager.ConnectInfo.UserName;
if (sText != null)
@ -149,46 +154,7 @@ namespace IndianHealthService.ClinicalScheduling
}
private BMXNetConnectInfo.BMXNetEventDelegate m_bmxDelegate;
delegate void OnUpdateScheduleDelegate();
private void BMXNetEventHandler(Object obj, BMXNet.BMXNetEventArgs e)
{
try
{
if (e.BMXEvent == "BMXNet AutoFire")
{
Debug.Write("CGView caught AutoFire event.\n");
if (this == null)
return;
OnUpdateScheduleDelegate ousd = new OnUpdateScheduleDelegate(OnUpdateSchedule);
this.BeginInvoke(ousd);
return;
}
if (e.BMXEvent != "BSDX SCHEDULE")
{
return;
}
string sResourceName;
for (int j=0; j < m_Document.m_sResourcesArray.Count; j++)
{
sResourceName = m_Document.m_sResourcesArray[j].ToString();
if (e.BMXParam == sResourceName)
{
OnUpdateScheduleDelegate ousd = new OnUpdateScheduleDelegate(OnUpdateSchedule);
if (this == null)
return;
this.BeginInvoke(ousd);
Debug.Write("CGView caught BSDX SCHEDULE event.\n");
break;
}
}
}
catch (Exception ex)
{
Debug.Write(ex.Message);
}
}
#endregion initialization
@ -650,7 +616,7 @@ namespace IndianHealthService.ClinicalScheduling
this.tvSchedules.HotTracking = true;
this.tvSchedules.Location = new System.Drawing.Point(0, 0);
this.tvSchedules.Name = "tvSchedules";
this.tvSchedules.Size = new System.Drawing.Size(128, 437);
this.tvSchedules.Size = new System.Drawing.Size(128, 395);
this.tvSchedules.Sorted = true;
this.tvSchedules.TabIndex = 1;
this.tvSchedules.AfterSelect += new System.Windows.Forms.TreeViewEventHandler(this.tvSchedules_AfterSelect);
@ -697,7 +663,7 @@ namespace IndianHealthService.ClinicalScheduling
this.panelRight.Dock = System.Windows.Forms.DockStyle.Right;
this.panelRight.Location = new System.Drawing.Point(941, 0);
this.panelRight.Name = "panelRight";
this.panelRight.Size = new System.Drawing.Size(128, 437);
this.panelRight.Size = new System.Drawing.Size(128, 395);
this.panelRight.TabIndex = 3;
this.panelRight.Visible = false;
//
@ -795,7 +761,7 @@ namespace IndianHealthService.ClinicalScheduling
this.panelCenter.Dock = System.Windows.Forms.DockStyle.Fill;
this.panelCenter.Location = new System.Drawing.Point(136, 24);
this.panelCenter.Name = "panelCenter";
this.panelCenter.Size = new System.Drawing.Size(802, 389);
this.panelCenter.Size = new System.Drawing.Size(802, 347);
this.panelCenter.TabIndex = 7;
//
// calendarGrid1
@ -817,7 +783,7 @@ namespace IndianHealthService.ClinicalScheduling
this.calendarGrid1.Name = "calendarGrid1";
this.calendarGrid1.Resources = ((System.Collections.ArrayList)(resources.GetObject("calendarGrid1.Resources")));
this.calendarGrid1.SelectedAppointment = 0;
this.calendarGrid1.Size = new System.Drawing.Size(802, 389);
this.calendarGrid1.Size = new System.Drawing.Size(802, 347);
this.calendarGrid1.StartDate = new System.DateTime(2003, 1, 27, 0, 0, 0, 0);
this.calendarGrid1.TabIndex = 0;
this.calendarGrid1.TimeScale = 20;
@ -825,6 +791,7 @@ namespace IndianHealthService.ClinicalScheduling
this.calendarGrid1.CGAppointmentAdded += new IndianHealthService.ClinicalScheduling.CalendarGrid.CGAppointmentChangedHandler(this.calendarGrid1_CGAppointmentAdded);
this.calendarGrid1.CGSelectionChanged += new IndianHealthService.ClinicalScheduling.CalendarGrid.CGSelectionChangedHandler(this.calendarGrid1_CGSelectionChanged);
this.calendarGrid1.DoubleClick += new System.EventHandler(this.calendarGrid1_DoubleClick);
this.calendarGrid1.MouseEnter += new System.EventHandler(this.calendarGrid1_MouseEnter);
//
// ctxCalendarGrid
//
@ -909,7 +876,7 @@ namespace IndianHealthService.ClinicalScheduling
//
this.panelBottom.Controls.Add(this.statusBar1);
this.panelBottom.Dock = System.Windows.Forms.DockStyle.Bottom;
this.panelBottom.Location = new System.Drawing.Point(136, 413);
this.panelBottom.Location = new System.Drawing.Point(136, 371);
this.panelBottom.Name = "panelBottom";
this.panelBottom.Size = new System.Drawing.Size(802, 24);
this.panelBottom.TabIndex = 8;
@ -927,7 +894,7 @@ namespace IndianHealthService.ClinicalScheduling
//
this.splitter1.Location = new System.Drawing.Point(128, 24);
this.splitter1.Name = "splitter1";
this.splitter1.Size = new System.Drawing.Size(8, 413);
this.splitter1.Size = new System.Drawing.Size(8, 371);
this.splitter1.TabIndex = 9;
this.splitter1.TabStop = false;
//
@ -936,7 +903,7 @@ namespace IndianHealthService.ClinicalScheduling
this.splitter2.Dock = System.Windows.Forms.DockStyle.Right;
this.splitter2.Location = new System.Drawing.Point(938, 24);
this.splitter2.Name = "splitter2";
this.splitter2.Size = new System.Drawing.Size(3, 413);
this.splitter2.Size = new System.Drawing.Size(3, 371);
this.splitter2.TabIndex = 10;
this.splitter2.TabStop = false;
//
@ -948,7 +915,7 @@ namespace IndianHealthService.ClinicalScheduling
// CGView
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(1069, 437);
this.ClientSize = new System.Drawing.Size(1069, 395);
this.Controls.Add(this.panelCenter);
this.Controls.Add(this.panelBottom);
this.Controls.Add(this.splitter2);
@ -1060,6 +1027,7 @@ namespace IndianHealthService.ClinicalScheduling
#endregion
#region AppointmentMenu Handlers
private void mnuAppointment_Popup(object sender, System.EventArgs e)
@ -1511,7 +1479,13 @@ namespace IndianHealthService.ClinicalScheduling
return;
}
//If this Document has no resources then use it (happens when the GUI has nothing open, typically after log-in)
//So if it is not a view that's already open, it means we have to grab the data for
//So we tell the user to wait wait wait
this.Cursor = Cursors.WaitCursor;
this.LoadSplash(); //Open "Loading" splash
//If this Document has no resources then use it (happens when the GUI has nothing open, typically after log-in)
//Else, create a new document
CGDocument doc;
if (this.Document.m_sResourcesArray.Count == 0)
@ -1547,7 +1521,7 @@ namespace IndianHealthService.ClinicalScheduling
//We are doing this--Again?
v =this.DocManager.GetViewByResource(sSelectedTreeResourceArray);
//Position the Grid
//Position the Grid to start at a certain day.
//XXX: This must be a better way to do this.
v.dateTimePicker1.Value = dDate;
v.StartDate = doc.StartDate;
@ -1627,6 +1601,10 @@ namespace IndianHealthService.ClinicalScheduling
v.calendarGrid1.SetOverlapTable();
v.calendarGrid1.Refresh();
// Set cursor back and stop splash screen
this.Cursor = Cursors.Default;
StopSplash();
}
private void LoadTree()
@ -2223,23 +2201,116 @@ namespace IndianHealthService.ClinicalScheduling
}
}
#region BMX Event Processing and Callbacks
/// <summary>
/// Loosely typed delegate used several times below.
/// </summary>
delegate void OnUpdateScheduleDelegate();
/// <summary>
/// Subscription point for each CGView to process BMX events polled from the server
/// </summary>
/// <param name="obj">Not used</param>
/// <param name="e">BMXEvent Args:
/// e.BMXEvent is free text for Event Type; e.BMXParam is free text for Event Arguments</param>
private void BMXNetEventHandler(Object obj, BMXNet.BMXNetEventArgs e)
{
try
{
// if this class is undefined (e.g. if the user just closed the form, do nothing
if (this == null) return;
// if event is Autofire event
if (e.BMXEvent == "BMXNet AutoFire")
{
Debug.Write("CGView caught AutoFire event.\n");
//Create a delegate to OnUpdateSchedule and call Async
//Once Async Call is done, go to OnUpdateScheduleCallback
OnUpdateScheduleDelegate ousd = new OnUpdateScheduleDelegate(OnUpdateSchedule);
ousd.BeginInvoke(OnUpdateScheduleCallback, null);
return;
}
// if event is BSDX SCHEDULE
else if (e.BMXEvent == "BSDX SCHEDULE")
{
//See if any of the resources in the event argument matches BSDX Schedule.
//If yes, fire off the delegate
string sResourceName;
for (int j = 0; j < m_Document.m_sResourcesArray.Count; j++)
{
sResourceName = m_Document.m_sResourcesArray[j].ToString();
if (e.BMXParam == sResourceName)
{
Debug.Write("CGView caught BSDX SCHEDULE event.\n");
//Create a delegate to OnUpdateSchedule and call Async
//Once Async Call is done, go to OnUpdateScheduleCallb
OnUpdateScheduleDelegate ousd = new OnUpdateScheduleDelegate(OnUpdateSchedule);
ousd.BeginInvoke(OnUpdateScheduleCallback, null);
break;
}
}
}
}
catch (Exception ex)
{
Debug.Write(ex.Message);
}
}
/// <summary>
/// Update Appointments and Availabilites using Document.RefreshDocumentAsync on a different thread
/// </summary>
/// <remarks>
/// This method is expected to be called asynchornously.
/// </remarks>
public void OnUpdateSchedule()
{
try
{
this.Cursor = Cursors.WaitCursor;
m_Document.RefreshDocument();
m_Document.RefreshDocumentAsync(); //new
}
catch (Exception ex)
{
MessageBox.Show("Unable to refresh document " + ex.Message, "Clinical Scheduling");
}
finally
{
this.Cursor = Cursors.Default;
}
}
/// <summary>
/// Callback for when OnUpdateSchedule is done. Triggers the Grid to redraw itself by calling UpdateArrays.
/// </summary>
/// <param name="itfAR">not used</param>
/// <remarks>Calls UpdateArrays via this.Invoke to make sure that the grid is redrawn on the UI thread</remarks>
private void OnUpdateScheduleCallback(IAsyncResult itfAR)
{
OnUpdateScheduleDelegate d = new OnUpdateScheduleDelegate(UpdateArrays);
this.Invoke(d);
}
/// <summary>
/// Create a new event in RPMS. Wrapper around BMXConnectInfo.RaiseEvent
/// </summary>
/// <param name="sEvent">Name of Event to Raise</param>
/// <param name="sParams">Parameter of Event to Raise</param>
public void RaiseRPMSEvent(string sEvent, string sParams)
{
try
{
//Signal RPMS to raise an event
m_ConnectInfo.RaiseEvent(sEvent, sParams, true);
}
catch (Exception ex)
{
Debug.Write(ex.Message);
}
}
#endregion
/// <summary>
/// This is how you set how the grid will look
/// </summary>
@ -2250,10 +2321,12 @@ namespace IndianHealthService.ClinicalScheduling
// This is where you set how the grid will look
try
{
this.calendarGrid1.AvailabilityArray = this.m_Document.AvailabilityArray;
//Tell the grid about Avails, Appts, and Resources.
this.calendarGrid1.AvailabilityArray = this.m_Document.AvailabilityArray;
//Appts are cloned b/c if we tie into the class directly, we shoot off errors when we manipulate it.
this.calendarGrid1.Appointments = (CGAppointments)this.m_Document.Appointments.Clone(); //smh new line again
this.calendarGrid1.Resources = this.m_Document.Resources;
// this.calendarGrid1.Columns = 7; //test
// this.calendarGrid1.StartDate = DateTime.Parse("10-10-2007"); // another test
//Redraw the calendar grid
this.calendarGrid1.OnUpdateArrays(); // this draws the Calendar
this.lblResource.Text = this.m_Document.DocName;
this.calendarGrid1.Invalidate();
@ -2264,19 +2337,6 @@ namespace IndianHealthService.ClinicalScheduling
}
}
public void RaiseRPMSEvent(string sEvent, string sParams)
{
try
{
//Signal RPMS to raise an event
m_ConnectInfo.RaiseEvent(sEvent, sParams, true);
}
catch (Exception ex)
{
Debug.Write(ex.Message);
}
}
private void SchedulingManagement()
{
try
@ -2371,7 +2431,25 @@ namespace IndianHealthService.ClinicalScheduling
#region Events
private void CGView_Load(object sender, System.EventArgs e)
/// <summary>
/// Special import to get the GetActiveWindow method from Win32
/// </summary>
/// <returns>Windows Handle number for Foregreound Active Window</returns>
[DllImport("user32.dll")]
static extern IntPtr GetActiveWindow();
/// <summary>
/// If a mouse enters the grid, check if the grid is on the active form first before stealing the focus
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void calendarGrid1_MouseEnter(object sender, EventArgs e)
{
if (GetActiveWindow() == this.Handle)
calendarGrid1.Focus();
}
private void CGView_Load(object sender, System.EventArgs e)
{
Debug.Assert (this.Document != null);
@ -3162,5 +3240,8 @@ namespace IndianHealthService.ClinicalScheduling
_loadingSplash.RemoteClose();
}
}//End class
}

View File

@ -70,6 +70,7 @@
this.m_gridCells = new CGCells();
this.m_selectedRange = new CGRange();
this.m_SelectedAppointments = new CGAppointments();
//this.m_Appointments = new CGAppointments();
this.m_dtStart = new DateTime(2003, 1, 27);
this.m_ApptOverlapTable = new Hashtable();
this.m_ColumnInfoTable = new Hashtable();
@ -88,12 +89,6 @@
this.m_sfHour.LineAlignment = StringAlignment.Center;
this.m_sfHour.Alignment = StringAlignment.Far;
this.m_bInitialUpdate = false;
this.MouseEnter += new EventHandler(CalendarGrid_MouseEnter);
}
void CalendarGrid_MouseEnter(object sender, EventArgs e)
{
this.Focus();
}
private Rectangle AdjustRectForOverlap()

View File

@ -38,7 +38,7 @@
| System.Windows.Forms.AnchorStyles.Right)));
this.lblLoading.AutoSize = true;
this.lblLoading.Font = new System.Drawing.Font("Tahoma", 48F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.lblLoading.Location = new System.Drawing.Point(228, 181);
this.lblLoading.Location = new System.Drawing.Point(138, 108);
this.lblLoading.Name = "lblLoading";
this.lblLoading.Size = new System.Drawing.Size(255, 77);
this.lblLoading.TabIndex = 0;
@ -50,12 +50,11 @@
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.BackColor = System.Drawing.SystemColors.ControlLightLight;
this.ClientSize = new System.Drawing.Size(722, 449);
this.ClientSize = new System.Drawing.Size(537, 315);
this.Controls.Add(this.lblLoading);
this.ForeColor = System.Drawing.SystemColors.ControlLight;
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
this.Name = "LoadingSplash";
this.Opacity = 0.8D;
this.ShowIcon = false;
this.ShowInTaskbar = false;
this.Text = "Form1";