source: Scheduling/branches/BMX4Support/CGDocumentManager.cs@ 1194

Last change on this file since 1194 was 1194, checked in by Sam Habiel, 13 years ago

All changes to support BMX4. Now works with BMX 4.
AssemblyInfo: Bumped to 1.6 (will be 1.7 pending server changes).
Removed BMXNet23.dll and added BMXNET40.dll and BMXWIN40.dll.
Actual changes to support BMX 4 in the code:
All references to DocManager.ConnectInfo.bmxNetLib substituted with CGDocumentManager.Current.RemoteSession everywhere.
All Events use RemoteSession.EventServices APIs.
All references to DUZ use RemoteSession.User APIs.
All references to BMXNetLib.Piece changed to M.Piece.
Added RPC Logging Capability courtesy of BMX4.
Extensive changes in the Main[] class CGDocumentManager:

  • Added references to IndianHealthService.BMXNet.WinForm
  • Removed references to BMXNetLib and changed to RemoteSession
  • Singleton Instance constructor now private (overdue change).
  • Use new Event Framework part of Remote Session.
  • Login code totally rewritten to use BMXWIN40.dll.
  • RPMSDataTable references changed to TableFromCommand or TableFromSQL.

DAL:

File size: 53.2 KB
Line 
1/* Main Class...:
2 * Original Author: Horace Whitt
3 * Current Author and Maintainer: Sam Habiel
4 * License: LGPL. http://www.gnu.org/licenses/lgpl-2.1.html
5*/
6
7using System;
8using System.Windows.Forms;
9using System.Collections;
10using System.Data;
11using System.Diagnostics;
12using System.Threading;
13using IndianHealthService.BMXNet;
14using IndianHealthService.BMXNet.WinForm;
15using IndianHealthService.BMXNet.WinForm.Configuration; //grrrr... too many namespaces here...
16using Mono.Options;
17using System.Runtime.InteropServices;
18using System.Globalization;
19
20namespace IndianHealthService.ClinicalScheduling
21{
22 /// <summary>
23 /// Main Worker. Handles sub-forms.
24 /// </summary>
25 public class CGDocumentManager //: System.Windows.Forms.Form
26 {
27 #region Member Variables
28
29 private static CGDocumentManager _current;
30 private Hashtable _views = new Hashtable(); //Returns the list of currently opened documents
31 private Hashtable m_AVViews = new Hashtable(); // List of currently opened CGAVViews
32 private string m_sWindowText = "Clinical Scheduling"; //Default Window Text
33 private bool m_bSchedManager = false; // Do you have the XUPROGMODE or BSDXZMGR?
34 private bool m_bExitOK = true; // Okay to exit program? Used to control Re-logins. Default true.
35 public string m_sHandle = "0"; // Not Used
36
37 //Connection variables (tied to command line parameters /a /v /s /p /e)
38 private string m_AccessCode="";
39 private string m_VerifyCode="";
40 private string m_Server="";
41 private int m_Port=0;
42 private string m_Encoding=""; //Encoding is "" by default;
43
44 //Globalization Object (tied to command line parameter /culture)
45 private string m_CultureName = "";
46
47 //Data Access Layer
48 private DAL _dal = null;
49
50 //M Connection member variables
51 private DataSet m_dsGlobal = null; // Holds all user data
52
53 //Custom Printing
54 private Printing m_PrintingObject = null;
55 #endregion
56
57 #region Properties
58
59 public WinFramework WinFramework { get; private set; } // Login Manager
60 public RemoteSession RemoteSession { get; private set; } // Data Sesssion against the RPMS/VISTA server
61 public RPCLogger RPCLogger { get; private set; } // Logger for RPCs
62
63 /// <summary>
64 /// True if the current user holds the BSDXZMGR or XUPROGMODE keys in RPMS
65 /// </summary>
66 public bool ScheduleManager
67 {
68 get
69 {
70 return m_bSchedManager;
71 }
72 }
73
74 /// <summary>
75 /// Holds the user and division
76 /// </summary>
77 public string WindowText
78 {
79 get
80 {
81 return m_sWindowText;
82 }
83 }
84
85 /// <summary>
86 /// This dataset contains tables used by the entire application
87 /// </summary>
88 public DataSet GlobalDataSet
89 {
90 get
91 {
92 return m_dsGlobal;
93 }
94 set
95 {
96 m_dsGlobal = value;
97 }
98 }
99
100 /// <summary>
101 /// User Preferences Auto Property
102 /// </summary>
103 public UserPreferences UserPreferences { get; private set; }
104
105 /// <summary>
106 /// Returns the single CGDocumentManager object
107 /// </summary>
108 public static CGDocumentManager Current
109 {
110 get
111 {
112 return _current;
113 }
114 }
115
116
117 /// <summary>
118 /// Returns the list of currently opened documents
119 /// </summary>
120 public Hashtable Views
121 {
122 get
123 {
124 return _views;
125 }
126 }
127
128 /// <summary>
129 /// Returns the list of currently opened CGAVViews
130 /// </summary>
131 public Hashtable AvailabilityViews
132 {
133 get
134 {
135 return this.m_AVViews;
136 }
137 }
138
139 public DAL DAL
140 {
141 get { return this._dal; }
142 }
143
144 public Printing PrintingObject
145 {
146 get
147 {
148 return this.m_PrintingObject;
149 }
150 }
151 #endregion
152
153 /// <summary>
154 /// Private constructor for singleton instance.
155 /// </summary>
156 private CGDocumentManager()
157 {
158 }
159
160
161#if DEBUG
162 //To write to the console
163 [DllImport("kernel32.dll")]
164 static extern bool AttachConsole(int dwProcessId);
165 private const int ATTACH_PARENT_PROCESS = -1;
166#endif
167 /// <summary>
168 /// Main Entry Point
169 /// </summary>
170 /// <param name="args">We accept the following Arguments:
171 /// /s or -s = Server ip address or name
172 /// /p or -p = port number (must be numeric)
173 /// /a or -a = Access Code
174 /// /v or -v = Verify Code
175 /// /e or -e = Encoding (name of encoding as known to windows, such as windows-1256)
176 /// /culture or -culture = Culture Name for UI Culture if you wish to override the Windows Culture
177 /// </param>
178 /// <remarks>
179 /// Encoding decision is complex. This is the order of priority:
180 /// - If the M DB runs in UTF-8, that's what we are going to use.
181 /// - If that's not so, /e sets the default encoding. If /e is a non-existent encoding, move to next step.
182 /// - If /e is not supplied or is not recognized, the default encoding is the Windows default Encoding for the user.
183 /// </remarks>
184 [STAThread()]
185 static void Main(string[] args)
186 {
187 //Application wide error handler for unhandled errors (later I figure out that's only for WinForm ex'es)
188 Application.SetUnhandledExceptionMode(UnhandledExceptionMode.ThrowException);
189 Application.ThreadException += new ThreadExceptionEventHandler(App_ThreadException);
190
191 // Add the event handler for handling non-UI thread exceptions to the event.
192 AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(App_DomainException);
193
194#if DEBUG
195 // Print console messages to console if launched from console
196 // Note: Imported From kernel32.dll
197 AttachConsole(ATTACH_PARENT_PROCESS);
198#endif
199
200#if TRACE
201 DateTime startLoadTime = DateTime.Now;
202#endif
203
204 //Store a class instance of manager. Actual constructor does nothing.
205 _current = new CGDocumentManager();
206
207 //Get command line options; store in private class wide variables
208 var opset = new OptionSet() {
209 { "s=", s => _current.m_Server = s },
210 { "p=", p => _current.m_Port = int.Parse(p) },
211 { "a=", a => _current.m_AccessCode = a },
212 { "v=", v => _current.m_VerifyCode = v },
213 { "e=", e => _current.m_Encoding = e},
214 { "culture=", culture => _current.m_CultureName = culture }
215 };
216
217 opset.Parse(args);
218
219 //Init app
220 bool isEverythingOkay = _current.InitializeApp();
221
222 //if an error occurred, break out.
223 if (!isEverythingOkay) return;
224
225 //Create the first empty document
226 //A document holds the resources, appointments, and availabilites
227 //SAM: Good place for break point
228 CGDocument doc = new CGDocument();
229 doc.DocManager = _current;
230
231 //Create new View
232 //A view is a specific arrangement of appointments and availabilites that constitute a document
233 CGView view = new CGView();
234 view.InitializeDocView(doc, _current, doc.StartDate, _current.WindowText);
235
236 //Handle BMX Event
237 Application.DoEvents();
238
239 //test
240 //doc.ThrowException();
241 //test
242
243#if TRACE
244 DateTime EndLoadTime = DateTime.Now;
245 TimeSpan LoadTime = EndLoadTime - startLoadTime;
246 Debug.Write("Load Time for GUI is " + LoadTime.Seconds + " s & " + LoadTime.Milliseconds + " ms\n");
247#endif
248
249 view.Show();
250 view.Activate();
251
252 Application.Run();
253 }
254
255 /// <summary>
256 /// Exception handler for application errors. Only for WinForm Errors.
257 /// </summary>
258 /// <remarks>Never tested. I can't get an error to go here!</remarks>
259 /// <param name="sender"></param>
260 /// <param name="e"></param>
261 static void App_ThreadException(object sender, ThreadExceptionEventArgs e)
262 {
263 string msg = "A problem has occured in this applicaton. \r\n\r\n" +
264 "\t" + e.Exception.Message + "\r\n\r\n" +
265 "Would you like to continue the application?";
266
267 DialogResult res = MessageBox.Show(msg, "Unexpected Error", MessageBoxButtons.YesNo);
268
269 if (res == DialogResult.Yes) return;
270 else Application.Exit();
271 }
272
273 /// <summary>
274 /// If we are here, we are dead meat.
275 /// </summary>
276 /// <param name="sender"></param>
277 /// <param name="e"></param>
278 static void App_DomainException(object sender, UnhandledExceptionEventArgs e)
279 {
280 if (e.ExceptionObject is System.Net.Sockets.SocketException)
281 {
282 MessageBox.Show("Looks like we lost our connection with the server\nClick OK to terminate the application.");
283 }
284 else
285 {
286 Exception ex = e.ExceptionObject as Exception;
287
288 string msg = "A problem has occured in this applicaton. \r\n\r\n" +
289 "\t" + ex.InnerException.Message;
290
291 MessageBox.Show(msg, "Unexpected Error");
292 }
293 }// here application terminates
294
295 #region BMXNet Event Handler
296 private void CDocMgrEventHandler(Object obj, RemoteEventArgs e)
297 {
298 if (e.EventType == "BSDX CALL WORKSTATIONS")
299 {
300 string sParam = "";
301 string sDelim="~";
302 sParam += this.RemoteSession.User.Name + sDelim;
303 sParam += this.m_sHandle + sDelim;
304 sParam += Application.ProductVersion + sDelim;
305 sParam += this._views.Count.ToString();
306 _current.RemoteSession.EventServices.TriggerEvent("BSDX WORKSTATION REPORT", sParam, true);
307 }
308 if (e.EventType == "BSDX ADMIN MESSAGE")
309 {
310 string sMsg = e.EventType;
311 ShowAdminMsgDelegate samd = new ShowAdminMsgDelegate(ShowAdminMsg);
312 samd.Invoke(sMsg);
313 }
314 if (e.EventType == "BSDX ADMIN SHUTDOWN")
315 {
316 string sMsg = e.Details;
317 CloseAllDelegate cad = new CloseAllDelegate(CloseAll);
318 cad.Invoke(sMsg);
319 }
320 }
321
322 delegate void ShowAdminMsgDelegate(string sMsg);
323
324 private void ShowAdminMsg(string sMsg)
325 {
326 MessageBox.Show(sMsg, "Message from Scheduling Administrator", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
327 }
328
329 #endregion BMXNet Event Handler
330
331
332 #region Methods & Events
333
334 /// <summary>
335 /// See InitializeApp(bool) below
336 /// </summary>
337 private bool InitializeApp()
338 {
339 return InitializeApp(false);
340 }
341
342 /// <summary>
343 /// Does a million things:
344 /// 1. Starts Connection and displays log-in dialogs
345 /// 2. Starts Splash screen
346 /// 3. Loads data tables
347 /// </summary>
348 /// <param name="bReLogin">Is the User logging in again from a currently running instance?
349 /// If so, display a dialog to collect access and verify codes.</param>
350 private bool InitializeApp(bool bReLogin)
351 {
352 //Note: There are 2 splashes -- one for being the parent of the log in forms
353 // the next is invoked async and updated async while the GUI is loading
354 // The reason is b/c an async form cannot be the parent of another that lies on the main thread
355
356 RPCLogger = new RPCLogger();
357
358 DSplash firstSplash = new DSplash();
359
360 firstSplash.Show();
361
362 /* IMPORTANT NOTE
363 * LOGIN CODE IS COPIED ALMOST VERBATIM FROM THE SCHEMABUILDER APPLICAITON;
364 * THE ONLY ONE I CAN FIND WHICH RELIES ON BMX 4 NEW WAYS WHICH I CAN'T FIGURE OUT
365 */
366 LoginProcess login;
367 this.WinFramework = WinFramework.CreateWithNetworkBroker(true, RPCLogger);
368
369 if (bReLogin) // if logging in again...
370 {
371 this.WinFramework.LoadConnectionSpecs(LocalPersistentStore.CreateDefaultStorage(true), "BSDX");
372 login = this.WinFramework.CreateLoginProcess();
373 login.AttemptUserInputLogin("Clincal Scheduling Log-in", 3, true, firstSplash);
374 goto DoneTrying;
375 }
376
377 // If server,port,ac,vc are supplied on command line, then try to connect...
378 else if (!String.IsNullOrEmpty(m_Server) && m_Port != 0 && !String.IsNullOrEmpty(m_AccessCode) && !String.IsNullOrEmpty(m_VerifyCode))
379 {
380 RpmsConnectionSpec spec = new RpmsConnectionSpec();
381 spec.IsDefault = true;
382 spec.Name = "Command Line Server";
383 spec.Port = m_Port;
384 spec.Server = m_Server;
385 spec.UseWindowsAuthentication = false; //for now
386 spec.UseDefaultNamespace = true; //for now
387 login = this.WinFramework.CreateLoginProcess();
388 login.AutoSetDivisionToLastLookup = false;
389 login.AttemptAccessVerifyLogin(spec, m_AccessCode, m_VerifyCode);
390 goto DoneTrying;
391 }
392
393 // if only server, port is supplied, then use these instead
394 else if (!String.IsNullOrEmpty(m_Server) && m_Port != 0)
395 {
396 RpmsConnectionSpec spec = new RpmsConnectionSpec();
397 spec.IsDefault = true;
398 spec.Name = "Command Line Server";
399 spec.Port = m_Port;
400 spec.Server = m_Server;
401 spec.UseWindowsAuthentication = false; //for now
402 spec.UseDefaultNamespace = true; //for now
403
404 RpmsConnectionSettings cxnSettings = new RpmsConnectionSettings
405 {
406 CommandLineConnectionSpec = spec
407 };
408
409 this.WinFramework.ConnectionSettings = cxnSettings;
410
411 login = this.WinFramework.CreateLoginProcess();
412 login.AutoSetDivisionToLastLookup = false;
413 login.AttemptUserInputLogin("Clinical Scheduling Log-in", 3, false, firstSplash);
414 goto DoneTrying;
415 }
416
417 // if nothing is supplied, fall back on the original dialog
418 else
419 {
420 this.WinFramework.LoadConnectionSpecs(LocalPersistentStore.CreateDefaultStorage(true), "BSDX");
421 login = this.WinFramework.CreateLoginProcess();
422 login.AutoSetDivisionToLastLookup = false;
423 login.AttemptUserInputLogin("Clincal Scheduling Log-in", 3, true, firstSplash);
424
425 goto DoneTrying;
426 }
427
428DoneTrying:
429 if (!login.WasSuccessful)
430 {
431 return false;
432 }
433
434 LocalSession local = this.WinFramework.LocalSession;
435
436 if ((this.WinFramework.Context.User.Division == null) && !this.WinFramework.AttemptUserInputSetDivision("Set Initial Division", firstSplash))
437 {
438 return false;
439 }
440
441
442
443 this.RemoteSession = this.WinFramework.PrimaryRemoteSession;
444
445 //Tie delegate to Events generated by BMX.
446 this.RemoteSession.EventServices.RpmsEvent += this.CDocMgrEventHandler;
447 //Disable polling
448 this.RemoteSession.EventServices.IsEventPollingEnabled = false;
449
450 //Second splash screens
451 //Show a splash screen while initializing; define delegates to remote thread
452 DSplash secondSplash = new DSplash();
453 DSplash.dSetStatus setStatusDelegate = new DSplash.dSetStatus(secondSplash.SetStatus);
454 DSplash.dAny closeSplashDelegate = new DSplash.dAny(secondSplash.RemoteClose);
455 DSplash.dProgressBarSet setMaxProgressDelegate = new DSplash.dProgressBarSet(secondSplash.RemoteProgressBarMaxSet);
456 DSplash.dProgressBarSet setProgressDelegate = new DSplash.dProgressBarSet(secondSplash.RemoteProgressBarValueSet);
457
458 //Start new thread for the Splash screen.
459 Thread threadSplash = new Thread(new ParameterizedThreadStart(frm => ((DSplash)frm).ShowDialog()));
460 threadSplash.IsBackground = true; //expendable thread -- exit even if still running.
461 threadSplash.Name = "Splash Thread";
462 threadSplash.Start(secondSplash);
463
464 firstSplash.Close(); // close temporary splash now that the new one is up and running
465
466 //There are 21 steps to load the application. That's max for the progress bar.
467 setMaxProgressDelegate(21);
468
469 // smh--not used: System.Configuration.ConfigurationManager.GetSection("appSettings");
470 setStatusDelegate("Connecting to VISTA");
471
472
473 /*
474 //Try to connect using supplied values for Server and Port
475 //Why am I doing this? The library BMX net uses prompts for access and verify code
476 //whether you can connect or not. Not good. So I test first whether
477 //we can connect at all by doing a simple connection and disconnect.
478 //TODO: Make this more robust by sending a TCPConnect message and seeing if you get a response
479 if (m_Server != "" && m_Port != 0)
480 {
481 System.Net.Sockets.TcpClient tcpClient = new System.Net.Sockets.TcpClient();
482 try
483 {
484 tcpClient.Connect(m_Server, m_Port); // open it
485 tcpClient.Close(); // then close it
486 }
487 catch (System.Net.Sockets.SocketException)
488 {
489 m_ds.RemoteMsgBox("Can't connect to server! Network Error");
490 return false;
491 }
492 }
493
494
495 bool bRetry = true;
496
497 // Do block is Log-in logic
498 do
499 {
500 // login crap
501 try
502 {
503 // Not my code
504 if (bReLogin == true)
505 {
506 //Prompt for Access and Verify codes
507 _current.m_ConnectInfo.LoadConnectInfo("", "");
508 }
509 // My code -- buts looks so ugly!
510 // Checks the passed parameters stored in the class variables
511 else
512 {
513 if (m_Server != String.Empty && m_Port != 0 && m_AccessCode != String.Empty
514 && m_VerifyCode != String.Empty)
515 {
516 m_ConnectInfo.LoadConnectInfo(m_Server, m_Port, m_AccessCode, m_VerifyCode);
517 }
518 else if (m_Server != String.Empty && m_Port != 0)
519 m_ConnectInfo.LoadConnectInfo(m_Server, m_Port, "", "");
520 else
521 m_ConnectInfo.LoadConnectInfo();
522 }
523 bRetry = false;
524 }
525 catch (System.Net.Sockets.SocketException)
526 {
527 m_ds.RemoteMsgBox("Cannot connect to VistA. Network Error");
528 }
529 catch (BMXNetException ex)
530 {
531 if (m_ds.RemoteMsgBox("Unable to connect to VistA. " + ex.Message, "Clinical Scheduling", MessageBoxButtons.RetryCancel) == DialogResult.Retry)
532 {
533 bRetry = true;
534 //I hate this, but this is how the library is designed. It throws an error if the user cancels. XXX: Won't fix library until BMX 4.0 port.
535 try { _current.m_ConnectInfo.ChangeServerInfo(); }
536 catch (Exception)
537 {
538 closeSplashDelegate();
539 bRetry = false;
540 return false; //tell main that it's a no go.
541 }
542 }
543 else
544 {
545 closeSplashDelegate();
546 bRetry = false;
547 return false; //tell main that it's a no go.
548 }
549 }
550 }while (bRetry == true);
551 */
552
553 //Printing Custom DLL. Perfect place for code injection!!!
554 //*************************************************
555 string DllLocation = string.Empty;
556 System.IO.DirectoryInfo di = new System.IO.DirectoryInfo(Application.StartupPath + @"\Printing\");
557 if (di.Exists)
558 {
559 System.IO.FileInfo[] rgFiles = di.GetFiles("*.dll");
560
561 foreach (System.IO.FileInfo fi in rgFiles)
562 {
563 DllLocation = fi.FullName;
564 }
565 }
566
567 PrintingCreator Creator = null;
568 if (DllLocation == string.Empty)
569 {
570 this.m_PrintingObject = new Printing();
571 }
572 else
573 {
574 System.Reflection.Assembly assembly = System.Reflection.Assembly.LoadFrom(DllLocation);
575 foreach (Type type in assembly.GetTypes())
576 {
577 if (type.IsClass == true & type.BaseType == typeof(PrintingCreator))
578 {
579 Creator = (PrintingCreator)Activator.CreateInstance(type);
580 break;
581 }
582 }
583 this.m_PrintingObject = Creator.PrintFactory();
584 }
585 //************************************************
586
587 //User Interface Culture (m_CultureName is set from the command line flag /culture)
588 //
589 //If passed, set that try that culture; fail over to Invariant Culture
590 if (m_CultureName != String.Empty)
591 {
592 try { Thread.CurrentThread.CurrentUICulture = new CultureInfo(m_CultureName); }
593 catch (CultureNotFoundException) { Thread.CurrentThread.CurrentUICulture = CultureInfo.InvariantCulture; }
594 }
595 //otherwise, use the Current Computer Culture, EVEN IF (!!) the UI Culture is different.
596 //this allows localization even if Windows still displays messages in English.
597 else
598 {
599 Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture;
600 }
601
602 _dal = new DAL(RemoteSession); // Data access layer
603
604 //Create global dataset
605 _current.m_dsGlobal = new DataSet("GlobalDataSet");
606
607 //Version info
608 // Table #1
609 setProgressDelegate(1);
610 setStatusDelegate("Getting Version Info from Server...");
611
612 DataTable ver = _dal.GetVersion("BSDX");
613 ver.TableName = "VersionInfo";
614 m_dsGlobal.Tables.Add(ver);
615
616 //How to extract the version numbers:
617 DataTable dtVersion = m_dsGlobal.Tables["VersionInfo"];
618 Debug.Assert(dtVersion.Rows.Count == 1);
619 DataRow rVersion = dtVersion.Rows[0];
620 string sMajor = rVersion["MAJOR_VERSION"].ToString();
621 string sMinor = rVersion["MINOR_VERSION"].ToString();
622 string sBuild = rVersion["BUILD"].ToString();
623 decimal fBuild = Convert.ToDecimal(sBuild);
624
625 //Make sure that the server is running the same version the client is.
626 Version x = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version;
627
628 //if version numbers mismatch, don't continue.
629 if (!(x.Major.ToString() == sMajor && x.Minor.ToString() == sMinor))
630 {
631 MessageBox.Show(
632 "Server runs version " + sMajor + "." + sMinor + "\r\n" +
633 "You are running " + x.ToString() + "\r\n\r\n" +
634 "Major, Minor and Build versions must match",
635 "Version Mismatch");
636 closeSplashDelegate();
637 return false;
638 }
639
640
641 //Change encoding
642 // Call #2
643 setProgressDelegate(2);
644 setStatusDelegate("Setting encoding...");
645 //PORT TODO: Set encoding
646 if (m_Encoding == String.Empty)
647 {
648 string utf8_server_support = RemoteSession.TransmitRPC("BMX UTF-8", "");
649
650 if (utf8_server_support == "1")
651 RemoteSession.ConnectionEncoding = System.Text.UTF8Encoding.UTF8;
652
653 }
654
655 //Set application context
656 // Call #3
657 setProgressDelegate(3);
658 setStatusDelegate("Setting Application Context to BSDXRPC...");
659 RemoteSession.AppContext = "BSDXRPC";
660
661 //User Preferences Object
662 setProgressDelegate(4); //next number is 6 b/c two calls
663 setStatusDelegate("Getting User Preferences from the Server...");
664
665 _current.UserPreferences = new UserPreferences(); // Constructor Does the calling to do that...
666
667 //Load global recordsets
668 string statusConst = "Loading VistA data tables...";
669 setStatusDelegate(statusConst);
670
671 string sCommandText;
672
673 //Schedule User Info
674 // Table #4
675 setProgressDelegate(6);
676 setStatusDelegate(statusConst + " Schedule User");
677 DataTable dtUser = _dal.GetUserInfo(RemoteSession.User.Duz);
678 dtUser.TableName = "SchedulingUser";
679 m_dsGlobal.Tables.Add(dtUser);
680 Debug.Assert(dtUser.Rows.Count == 1);
681
682 // Only one row and one column named "MANAGER". Set local var m_bSchedManager to true if Manager.
683 DataRow rUser = dtUser.Rows[0];
684 Object oUser = rUser["MANAGER"];
685 string sUser = oUser.ToString();
686 m_bSchedManager = (sUser == "YES") ? true : false;
687
688 //Get Access Types
689 // Table #5
690 setProgressDelegate(7);
691 setStatusDelegate(statusConst + " Access Types");
692 DataTable dtAccessTypes = _dal.GetAccessTypes(m_dsGlobal, "AccessTypes");
693
694 //Get Access Groups
695 // Table #6
696 setProgressDelegate(8);
697 setStatusDelegate(statusConst + " Access Groups");
698 LoadAccessGroupsTable();
699
700 //Build Primary Key for AccessGroup table
701 DataTable dtGroups = m_dsGlobal.Tables["AccessGroup"];
702 DataColumn dcKey = dtGroups.Columns["ACCESS_GROUP"];
703 DataColumn[] dcKeys = new DataColumn[1];
704 dcKeys[0] = dcKey;
705 dtGroups.PrimaryKey = dcKeys;
706
707 //Get Access Group Types (Combines Access Types and Groups)
708 //Optimization Note: Can eliminate Access type and Access Group Table
709 // But they are heavily referenced throughout the code.
710 // Table #7
711 setProgressDelegate(9);
712 setStatusDelegate(statusConst + " Access Group Types");
713 LoadAccessGroupTypesTable();
714
715 //Build Primary Key for AccessGroupType table
716 DataTable dtAGTypes = m_dsGlobal.Tables["AccessGroupType"];
717 DataColumn dcGTKey = dtAGTypes.Columns["ACCESS_GROUP_TYPEID"];
718 DataColumn[] dcGTKeys = new DataColumn[1];
719 dcGTKeys[0] = dcGTKey;
720 dtAGTypes.PrimaryKey = dcGTKeys;
721
722 //Build Data Relationship between AccessGroupType and AccessTypes tables
723 DataRelation dr = new DataRelation("AccessGroupType", //Relation Name
724 m_dsGlobal.Tables["AccessGroup"].Columns["BMXIEN"], //Parent
725 m_dsGlobal.Tables["AccessGroupType"].Columns["ACCESS_GROUP_ID"]); //Child
726 m_dsGlobal.Relations.Add(dr);
727
728 //ResourceGroup Table (Resource Groups by User)
729 // Table #8
730 // What shows up on the tree. The groups the user has access to.
731 setProgressDelegate(10);
732 setStatusDelegate(statusConst + " Resource Groups By User");
733 LoadResourceGroupTable();
734
735 //Resources by user
736 // Table #9
737 // Individual Resources
738 setProgressDelegate(11);
739 setStatusDelegate(statusConst + " Resources By User");
740 LoadBSDXResourcesTable();
741
742 //Build Primary Key for Resources table
743 DataColumn[] dc = new DataColumn[1];
744 dc[0] = m_dsGlobal.Tables["Resources"].Columns["RESOURCEID"];
745 m_dsGlobal.Tables["Resources"].PrimaryKey = dc;
746
747 //GroupResources table
748 // Table #10
749 // Resource Groups and Indivdual Resources together
750 setProgressDelegate(12);
751 setStatusDelegate(statusConst + " Group Resources");
752 LoadGroupResourcesTable();
753
754 //Build Primary Key for ResourceGroup table
755 dc = new DataColumn[1];
756 dc[0] = m_dsGlobal.Tables["ResourceGroup"].Columns["RESOURCE_GROUP"];
757 m_dsGlobal.Tables["ResourceGroup"].PrimaryKey = dc;
758
759 //Build Data Relationships between ResourceGroup and GroupResources tables
760 dr = new DataRelation("GroupResource", //Relation Name
761 m_dsGlobal.Tables["ResourceGroup"].Columns["RESOURCE_GROUP"], //Parent
762 m_dsGlobal.Tables["GroupResources"].Columns["RESOURCE_GROUP"]); //Child
763
764 m_dsGlobal.Relations.Add(dr);
765
766 //HospitalLocation table
767 //Table #11
768 setProgressDelegate(13);
769 setStatusDelegate(statusConst + " Clinics");
770 //cmd.CommandText = "SELECT BMXIEN 'HOSPITAL_LOCATION_ID', NAME 'HOSPITAL_LOCATION', DEFAULT_PROVIDER, STOP_CODE_NUMBER, INACTIVATE_DATE, REACTIVATE_DATE FROM HOSPITAL_LOCATION";
771 sCommandText = "BSDX HOSPITAL LOCATION";
772 RemoteSession.TableFromCommand(sCommandText, m_dsGlobal, "HospitalLocation");
773 Debug.Write("LoadGlobalRecordsets -- HospitalLocation loaded\n");
774
775 //Build Primary Key for HospitalLocation table
776 dc = new DataColumn[1];
777 DataTable dtTemp = m_dsGlobal.Tables["HospitalLocation"];
778 dc[0] = dtTemp.Columns["HOSPITAL_LOCATION_ID"];
779 m_dsGlobal.Tables["HospitalLocation"].PrimaryKey = dc;
780
781 //Build Data Relationships between Resources and HospitalLocation tables
782 dr = new DataRelation("HospitalLocationResource", //Relation Name
783 m_dsGlobal.Tables["HospitalLocation"].Columns["HOSPITAL_LOCATION_ID"], //Parent
784 m_dsGlobal.Tables["Resources"].Columns["HOSPITAL_LOCATION_ID"], false); //Child
785 m_dsGlobal.Relations.Add(dr);
786
787 //Build ScheduleUser table
788 //Table #12
789 setProgressDelegate(14);
790 setStatusDelegate(statusConst + " Schedule User");
791 this.LoadScheduleUserTable();
792
793 //Build Primary Key for ScheduleUser table
794 dc = new DataColumn[1];
795 dtTemp = m_dsGlobal.Tables["ScheduleUser"];
796 dc[0] = dtTemp.Columns["USERID"];
797 m_dsGlobal.Tables["ScheduleUser"].PrimaryKey = dc;
798
799 //Build ResourceUser table
800 //Table #13
801 //Acess to Resources by [this] User
802 setProgressDelegate(15);
803 setStatusDelegate(statusConst + " Resource User");
804 this.LoadResourceUserTable();
805
806 //Build Primary Key for ResourceUser table
807 dc = new DataColumn[1];
808 dtTemp = m_dsGlobal.Tables["ResourceUser"];
809 dc[0] = dtTemp.Columns["RESOURCEUSER_ID"];
810 m_dsGlobal.Tables["ResourceUser"].PrimaryKey = dc;
811
812 //Create relation between BSDX Resource and BSDX Resource User tables
813 dr = new DataRelation("ResourceUser", //Relation Name
814 m_dsGlobal.Tables["Resources"].Columns["RESOURCEID"], //Parent
815 m_dsGlobal.Tables["ResourceUser"].Columns["RESOURCEID"]); //Child
816 m_dsGlobal.Relations.Add(dr);
817
818 //Build active provider table
819 //Table #14
820 //TODO: Lazy load the provider table; no need to load in advance.
821 setProgressDelegate(16);
822 setStatusDelegate(statusConst + " Providers");
823 sCommandText = "SELECT BMXIEN, NAME FROM NEW_PERSON WHERE INACTIVE_DATE = '' AND BMXIEN > 1";
824 RemoteSession.TableFromSQL(sCommandText, m_dsGlobal, "Provider");
825 Debug.Write("LoadGlobalRecordsets -- Provider loaded\n");
826
827 //Build the HOLIDAY table
828 //Table #15
829 setProgressDelegate(17);
830 setStatusDelegate(statusConst + " Holiday");
831 sCommandText = "SELECT NAME, DATE FROM HOLIDAY WHERE INTERNAL[DATE] > '" + FMDateTime.Create(DateTime.Today).DateOnly.FMDateString + "'";
832 RemoteSession.TableFromSQL(sCommandText, m_dsGlobal, "HOLIDAY");
833 Debug.Write("LoadingGlobalRecordsets -- Holidays loaded\n");
834
835
836 //Save the xml schema
837 //m_dsGlobal.WriteXmlSchema(@"..\..\csSchema20060526.xsd");
838 //----------------------------------------------
839
840 setStatusDelegate("Setting Receive Timeout");
841 _current.RemoteSession.ReceiveTimeout = 30000; //30-second timeout
842
843#if DEBUG
844 _current.RemoteSession.ReceiveTimeout = 600000; //longer timeout for debugging
845#endif
846 // Event Subsriptions
847 setStatusDelegate("Subscribing to Server Events");
848 //Table #16
849 setProgressDelegate(18);
850 _current.RemoteSession.EventServices.Subscribe("BSDX SCHEDULE");
851 //Table #17
852 setProgressDelegate(19);
853 _current.RemoteSession.EventServices.Subscribe("BSDX CALL WORKSTATIONS");
854 //Table #18
855 setProgressDelegate(20);
856 _current.RemoteSession.EventServices.Subscribe("BSDX ADMIN MESSAGE");
857 //Table #19
858 setProgressDelegate(21);
859 _current.RemoteSession.EventServices.Subscribe("BSDX ADMIN SHUTDOWN");
860
861 _current.RemoteSession.EventServices.EventPollingInterval = 5000; //in milliseconds
862 _current.RemoteSession.EventServices.IsEventPollingEnabled = true;
863
864 //PORT TODO: No Autofire in BMX 4.0
865 //_current.RemoteSession.EventServices. = 12; //AutoFire every 12*5 seconds
866
867 //Close Splash Screen
868 closeSplashDelegate();
869
870 return true;
871
872 }
873
874
875
876 public void LoadAccessGroupsTable()
877 {
878 string sCommandText = "SELECT * FROM BSDX_ACCESS_GROUP";
879 RemoteSession.TableFromSQL(sCommandText, m_dsGlobal, "AccessGroup");
880 Debug.Write("LoadGlobalRecordsets -- AccessGroups loaded\n");
881 }
882
883 public void LoadAccessGroupTypesTable()
884 {
885 string sCommandText = "BSDX GET ACCESS GROUP TYPES";
886 RemoteSession.TableFromCommand(sCommandText, m_dsGlobal, "AccessGroupType");
887 Debug.Write("LoadGlobalRecordsets -- AccessGroupTypes loaded\n");
888 }
889
890 public void LoadBSDXResourcesTable()
891 {
892 string sCommandText = "BSDX RESOURCES^" + RemoteSession.User.Duz;
893 RemoteSession.TableFromCommand(sCommandText, m_dsGlobal, "Resources");
894 Debug.Write("LoadGlobalRecordsets -- Resources loaded\n");
895 }
896
897 public void LoadResourceGroupTable()
898 {
899 //ResourceGroup Table (Resource Groups by User)
900 //Table "ResourceGroup" contains all resource group names
901 //to which user has access
902 //Fields are: RESOURCE_GROUPID, RESOURCE_GROUP
903 string sCommandText = "BSDX RESOURCE GROUPS BY USER^" + RemoteSession.User.Duz;
904 RemoteSession.TableFromCommand(sCommandText, m_dsGlobal, "ResourceGroup");
905 Debug.Write("LoadGlobalRecordsets -- ResourceGroup loaded\n");
906 }
907
908 public void LoadGroupResourcesTable()
909 {
910 //Table "GroupResources" contains all active GROUP/RESOURCE combinations
911 //to which user has access based on entries in BSDX RESOURCE USER file
912 //If user has BSDXZMGR or XUPROGMODE keys, then ALL Group/Resource combinstions
913 //are returned.
914 //Fields are: RESOURCE_GROUPID, RESOURCE_GROUP, RESOURCE_GROUP_ITEMID, RESOURCE_NAME, RESOURCE_ID
915 string sCommandText = "BSDX GROUP RESOURCE^" + RemoteSession.User.Duz;
916 RemoteSession.TableFromCommand(sCommandText, m_dsGlobal, "GroupResources");
917 Debug.Write("LoadGlobalRecordsets -- GroupResources loaded\n");
918 }
919
920 public void LoadScheduleUserTable()
921 {
922 //Table "ScheduleUser" contains an entry for each user in File 200 (NEW PERSON)
923 //who possesses the BSDXZMENU security key.
924 string sCommandText = "BSDX SCHEDULE USER";
925 RemoteSession.TableFromCommand(sCommandText, m_dsGlobal, "ScheduleUser");
926 Debug.Write("LoadGlobalRecordsets -- ScheduleUser loaded\n");
927 }
928
929 public void LoadResourceUserTable()
930 {
931 //Table "ResourceUser" duplicates the BSDX RESOURCE USER File.
932 //NOTE: Column names are RESOURCEUSER_ID, RESOURCEID,
933 // OVERBOOK, MODIFY_SCHEDULE, USERID, USERID1
934 //string sCommandText = "SELECT BMXIEN RESOURCEUSER_ID, INTERNAL[RESOURCENAME] RESOURCEID, OVERBOOK, MODIFY_SCHEDULE, USERNAME USERID, INTERNAL[USERNAME] FROM BSDX_RESOURCE_USER";
935 LoadResourceUserTable(false);
936 }
937
938 public void LoadResourceUserTable(bool bAllUsers)
939 {
940 string sCommandText = @"SELECT BMXIEN RESOURCEUSER_ID, RESOURCENAME, INTERNAL[RESOURCENAME] RESOURCEID, OVERBOOK, MODIFY_SCHEDULE, MODIFY_APPOINTMENTS, USERNAME, INTERNAL[USERNAME] USERID FROM BSDX_RESOURCE_USER"; // WHERE INTERNAL[INSTITUTION]=" + m_ConnectInfo.DUZ2;
941
942 if (!bAllUsers)
943 {
944 sCommandText += String.Format(" WHERE INTERNAL[USERNAME] = {0}", RemoteSession.User.Duz);
945 }
946
947 RemoteSession.TableFromSQL(sCommandText, m_dsGlobal, "ResourceUser");
948 Debug.Write("LoadGlobalRecordsets -- ResourceUser loaded\n");
949 }
950
951
952 public void RegisterDocumentView(CGDocument doc, CGView view)
953 {
954 //Store the view in the list of views
955 this.Views.Add(view, doc);
956
957 //Hook into the view's 'closed' event
958 view.Closed += new EventHandler(ViewClosed);
959
960 //Hook into the view's mnuRPMSServer.Click event
961 view.mnuRPMSServer.Click += new EventHandler(mnuRPMSServer_Click);
962
963 //Hook into the view's mnuRPMSLogin.Click event
964 view.mnuRPMSLogin.Click += new EventHandler(mnuRPMSLogin_Click);
965
966 }
967
968 public void RegisterAVDocumentView(CGAVDocument doc, CGAVView view)
969 {
970 //Store the view in the list of views
971 this.AvailabilityViews.Add(view, doc);
972
973 //Hook into the view's 'closed' event
974 view.Closed += new EventHandler(AVViewClosed);
975 }
976
977 public CGAVView GetAVViewByResource(ArrayList sResourceArray)
978 {
979 if (sResourceArray == null)
980 return null;
981
982 bool bEqual = true;
983 foreach (CGAVView v in m_AVViews.Keys)
984 {
985 CGAVDocument d = v.Document;
986
987 bEqual = false;
988 if (d.Resources.Count == sResourceArray.Count)
989 {
990 bEqual = true;
991 for (int j = 0; j < sResourceArray.Count; j++)
992 {
993 if (sResourceArray.Contains(d.Resources[j]) == false)
994 {
995 bEqual = false;
996 break;
997 }
998 if (d.Resources.Contains(sResourceArray[j]) == false)
999 {
1000 bEqual = false;
1001 break;
1002 }
1003 }
1004 if (bEqual == true)
1005 return v;
1006 }
1007 }
1008 return null;
1009 }
1010 /// <summary>
1011 /// Return the first view having a resource array matching sResourceArray
1012 /// </summary>
1013 /// <param name="sResourceArray"></param>
1014 /// <returns></returns>
1015 public CGView GetViewByResource(ArrayList sResourceArray)
1016 {
1017 if (sResourceArray == null)
1018 return null;
1019
1020 bool bEqual = true;
1021 foreach (CGView v in _views.Keys)
1022 {
1023 CGDocument d = v.Document;
1024
1025 bEqual = false;
1026 if (d.Resources.Count == sResourceArray.Count)
1027 {
1028 bEqual = true;
1029 for (int j = 0; j < sResourceArray.Count; j++)
1030 {
1031 if (sResourceArray.Contains(d.Resources[j]) == false)
1032 {
1033 bEqual = false;
1034 break;
1035 }
1036 if (d.Resources.Contains(sResourceArray[j]) == false)
1037 {
1038 bEqual = false;
1039 break;
1040 }
1041 }
1042 if (bEqual == true)
1043 return v;
1044 }
1045 }
1046 return null;
1047 }
1048
1049 /// <summary>
1050 /// Removes view and Handles Disconnection from Database if no views are left.
1051 /// </summary>
1052 /// <param name="sender"></param>
1053 /// <param name="e"></param>
1054 private void ViewClosed(object sender, EventArgs e)
1055 {
1056 //Remove the sender from our document list
1057 Views.Remove(sender);
1058
1059 //If no documents left, then close RPMS connection & exit the application
1060 if ((Views.Count == 0)&&(this.AvailabilityViews.Count == 0)&&(m_bExitOK == true))
1061 {
1062 RemoteSession.EventServices.IsEventPollingEnabled = false;
1063 RemoteSession.EventServices.Unsubscribe("BSDX SCHEDULE");
1064 RemoteSession.Close();
1065 Application.Exit();
1066 }
1067 }
1068
1069 private void AVViewClosed(object sender, EventArgs e)
1070 {
1071 //Remove the sender from our document list
1072 this.AvailabilityViews.Remove(sender);
1073
1074 //If no documents left, then close RPMS connection & exit the application
1075 if ((Views.Count == 0)&&(this.AvailabilityViews.Count == 0)&&(m_bExitOK == true))
1076 {
1077 RemoteSession.Close();
1078 Application.Exit();
1079 }
1080 }
1081
1082 /// <summary>
1083 /// Not used
1084 /// </summary>
1085 private void KeepAlive()
1086 {
1087 foreach (CGView v in _views.Keys)
1088 {
1089 CGDocument d = v.Document;
1090 DateTime dNow = DateTime.Now;
1091 DateTime dLast = d.LastRefreshed;
1092 TimeSpan tsDiff = dNow - dLast;
1093 if (tsDiff.Seconds > 180)
1094 {
1095 for (int j = 0; j < d.Resources.Count; j++)
1096 {
1097 v.RaiseRPMSEvent("SCHEDULE-" + d.Resources[j].ToString(), "");
1098 }
1099
1100 break;
1101 }
1102 }
1103 }
1104
1105 /// <summary>
1106 /// Propogate availability updates to all sRresource's doc/views
1107 /// </summary>
1108 public void UpdateViews(string sResource, string sOldResource)
1109 {
1110 if (sResource == null)
1111 return;
1112 foreach (CGView v in _views.Keys)
1113 {
1114 CGDocument d = v.Document;
1115 for (int j = 0; j < d.Resources.Count; j++)
1116 {
1117 if ((sResource == "") || (sResource == ((string) d.Resources[j])) || (sOldResource == ((string) d.Resources[j])))
1118 {
1119 d.RefreshDocument();
1120 break;
1121 }
1122 }
1123 v.UpdateTree();
1124 }
1125 }
1126
1127 /// <summary>
1128 /// Propogate availability updates to all doc/views
1129 /// </summary>
1130 public void UpdateViews()
1131 {
1132 UpdateViews("","");
1133 foreach (CGView v in _views.Keys)
1134 {
1135 v.UpdateTree();
1136 }
1137 }
1138
1139 /// <summary>
1140 /// Calls each view associated with document Doc and closes it.
1141 /// </summary>
1142 public void CloseAllViews(CGDocument doc)
1143 {
1144 //iterate through all views and call update.
1145 Hashtable h = CGDocumentManager.Current.Views;
1146
1147 CGDocument d;
1148 int nTempCount = h.Count;
1149 do
1150 {
1151 nTempCount = h.Count;
1152 foreach (CGView v in h.Keys)
1153 {
1154 d = (CGDocument) h[v];
1155 if (d == doc)
1156 {
1157 v.Close();
1158 break;
1159 }
1160 }
1161 } while ((h.Count > 0) && (nTempCount != h.Count));
1162 }
1163
1164 /// <summary>
1165 /// Calls each view associated with Availability Doc and closes it.
1166 /// </summary>
1167 public void CloseAllViews(CGAVDocument doc)
1168 {
1169 //iterate through all views and call update.
1170 Hashtable h = CGDocumentManager.Current.AvailabilityViews;
1171
1172 CGAVDocument d;
1173 int nTempCount = h.Count;
1174 do
1175 {
1176 nTempCount = h.Count;
1177 foreach (CGAVView v in h.Keys)
1178 {
1179 d = (CGAVDocument) h[v];
1180 if (d == doc)
1181 {
1182 v.Close();
1183 break;
1184 }
1185 }
1186 } while ((h.Count > 0) && (nTempCount != h.Count));
1187
1188
1189 }
1190
1191 /// <summary>
1192 /// Accomplishes Changing the Server to which you connect
1193 /// </summary>
1194 /// <remarks>
1195 /// Parameter relog-in for InitializeApp forces initialize app to use
1196 /// 1. The server the user just picked and then BMX saved off to User Preferences
1197 /// 2. A new access and verify code pair
1198 /// </remarks>
1199 /// <param name="sender">unused</param>
1200 /// <param name="e">unused</param>
1201 private void mnuRPMSServer_Click(object sender, EventArgs e)
1202 {
1203 //Warn that changing servers will close all schedules
1204 if (MessageBox.Show("Are you sure you want to close all schedules and connect to a different VistA server?", "Clinical Scheduling", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning) != DialogResult.OK)
1205 return;
1206
1207 //Reconnect to RPMS and recreate all global recordsets
1208 try
1209 {
1210 // Close All, but tell the Close All method not to call Applicaiton.Exit since we still plan to continue.
1211 // Close All does not call Application.Exit, but CGView_Close handler does
1212 m_bExitOK = false;
1213 CloseAll();
1214 m_bExitOK = true;
1215
1216 //Used in Do loop
1217 //bool bRetry = true;
1218
1219 /*// Do Loop to deal with changing the server and the vagaries of user choices.
1220 do
1221 {
1222 try
1223 {
1224 //ChangeServerInfo does not re-login the user
1225 //It only changes the saved server information in the %APPDATA% folder
1226 //so it can be re-used when BMX tries to log in again.
1227 //Access and Verify code are prompted for in InitializeApp
1228 LoginProcess login = this.WinFramework.CreateLoginProcess();
1229 login.AttemptUserInputLogin("ReLog-in", 3, true, null);
1230 bRetry = false;
1231 }
1232 catch (Exception ex)
1233 {
1234 if (ex.Message == "User cancelled.")
1235 {
1236 bRetry = false;
1237 Application.Exit();
1238 return;
1239 }
1240 if (MessageBox.Show("Unable to connect to VistA. " + ex.Message , "Clinical Scheduling", MessageBoxButtons.RetryCancel) == DialogResult.Retry)
1241 {
1242 bRetry = true;
1243 }
1244 else
1245 {
1246 bRetry = false;
1247 Application.Exit();
1248 return;
1249 }
1250 }
1251 } while (bRetry == true);
1252 */
1253
1254 //Parameter for initialize app tells it that this is a re-login and forces a new access and verify code.
1255 bool isEverythingOkay = this.InitializeApp(true);
1256
1257 //if an error occurred, break out. This time we need to call Application.Exit since it's already running.
1258 if (!isEverythingOkay)
1259 {
1260 Application.Exit();
1261 return;
1262 }
1263
1264 //Otherwise, everything is okay. So open document and view, then show and activate view.
1265 CGDocument doc = new CGDocument();
1266 doc.DocManager = _current;
1267
1268 CGView view = new CGView();
1269 view.InitializeDocView(doc, _current, doc.StartDate, _current.WindowText);
1270
1271 view.Show();
1272 view.Activate();
1273
1274 //Application.Run need not be called b/c it is already running.
1275 }
1276 catch (Exception ex)
1277 {
1278 throw ex;
1279 }
1280
1281 }
1282
1283 /// <summary>
1284 /// Accomplishes Re-login into RPMS/VISTA. Now all logic is in this event handler.
1285 /// </summary>
1286 /// <param name="sender">not used</param>
1287 /// <param name="e">not used</param>
1288 private void mnuRPMSLogin_Click(object sender, EventArgs e)
1289 {
1290 mnuRPMSServer_Click(sender, e);
1291
1292 /* v 1.7 to support BMX 4 -- commented out -- smh
1293 //Warn that changing login will close all schedules
1294 if (MessageBox.Show("Are you sure you want to close all schedules and login to VistA?", "Clinical Scheduling", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning) != DialogResult.OK)
1295 return;
1296
1297 //Reconnect to RPMS and recreate all global recordsets
1298 try
1299 {
1300 // Close All, but tell the Close All method not to call Applicaiton.Exit since we still plan to continue.
1301 // Close All does not call Application.Exit, but CGView_Close handler does
1302 m_bExitOK = false;
1303 CloseAll();
1304 m_bExitOK = true;
1305
1306 LoginProcess login = this.WinFramework.CreateLoginProcess();
1307 login.AttemptUserInputLogin("Clincal Scheduling", 3, true, null);
1308 //m_ConnectInfo.bmxNetLib.StartLog(); //This line turns on logging of messages
1309
1310 if (!login.WasSuccessful)
1311 {
1312 return;
1313 }
1314
1315 LocalSession local = this.WinFramework.LocalSession;
1316
1317 if ((this.WinFramework.Context.User.Division == null) && !this.WinFramework.AttemptUserInputSetDivision("Set Initial Division", null))
1318 {
1319 return;
1320 }
1321
1322 this.RemoteSession = this.WinFramework.PrimaryRemoteSession;
1323
1324 //Parameter for initialize app tells it that this is a re-login and forces a new access and verify code.
1325 bool isEverythingOkay = this.InitializeApp(true);
1326
1327 //if an error occurred, break out. This time we need to call Application.Exit since it's already running.
1328 if (!isEverythingOkay)
1329 {
1330 Application.Exit();
1331 return;
1332 }
1333
1334 //Otherwise, everything is okay. So open document and view, then show and activate view.
1335 CGDocument doc = new CGDocument();
1336 doc.DocManager = _current;
1337
1338 CGView view = new CGView();
1339 view.InitializeDocView(doc, _current, doc.StartDate, _current.WindowText);
1340
1341 view.Show();
1342 view.Activate();
1343
1344 //Application.Run need not be called b/c it is already running.
1345 }
1346 catch (Exception ex)
1347 {
1348 throw ex;
1349 }
1350 */
1351 }
1352
1353 delegate void CloseAllDelegate(string sMsg);
1354
1355 private void CloseAll(string sMsg)
1356 {
1357 if (sMsg == "")
1358 {
1359 sMsg = "Scheduling System Shutting Down Immediately for Maintenance.";
1360 }
1361
1362 MessageBox.Show(sMsg, "Clinical Scheduling Administrator -- System Shutdown Notification", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
1363
1364 CloseAll();
1365 }
1366
1367 private void CloseAll()
1368 {
1369 //Close all documents, views and connections
1370 Hashtable h = CGDocumentManager.Current.Views;
1371 int nTempCount = h.Count;
1372 do
1373 {
1374 nTempCount = h.Count;
1375 foreach (CGView v in h.Keys)
1376 {
1377 v.Close();
1378 break;
1379 }
1380 } while ((h.Count > 0) && (nTempCount != h.Count));
1381
1382 h = CGDocumentManager.Current.AvailabilityViews;
1383 nTempCount = h.Count;
1384 do
1385 {
1386 nTempCount = h.Count;
1387 foreach (CGAVView v in h.Keys)
1388 {
1389 v.Close();
1390 break;
1391 }
1392 } while ((h.Count > 0) && (nTempCount != h.Count));
1393
1394 }
1395
1396 public delegate DataTable RPMSDataTableDelegate(string CommandString, string TableName);
1397
1398 public DataTable RPMSDataTable(string sSQL, string sTableName)
1399 {
1400 //Retrieves a recordset from RPMS
1401 string sErrorMessage = "";
1402 DataTable dtOut;
1403
1404 try
1405 {
1406 //System.IntPtr pHandle = this.Handle;
1407 RPMSDataTableDelegate rdtd = new RPMSDataTableDelegate(RemoteSession.TableFromCommand);
1408 //dtOut = (DataTable) this.Invoke(rdtd, new object[] {sSQL, sTableName});
1409 dtOut = RemoteSession.TableFromCommand(sSQL);
1410 dtOut.TableName = sTableName;
1411
1412 }
1413
1414 catch (Exception ex)
1415 {
1416 sErrorMessage = "CGDocumentManager.RPMSDataTable error: " + ex.Message;
1417 throw ex;
1418 }
1419
1420 return dtOut;
1421
1422 }
1423
1424 public void ChangeDivision(System.Windows.Forms.Form frmCaller)
1425 {
1426 WinFramework.AttemptUserInputSetDivision("Change Division", frmCaller);
1427
1428 RemoteSession = WinFramework.PrimaryRemoteSession;
1429
1430 foreach (CGView v in _views.Keys)
1431 {
1432 v.InitializeDocView(v.Document.DocName);
1433 v.Document.RefreshDocument();
1434 }
1435 }
1436
1437 public void ViewRefresh()
1438 {
1439 foreach (CGView v in _views.Keys)
1440 {
1441 try
1442 {
1443 v.Document.RefreshDocument();
1444 }
1445 catch (Exception ex)
1446 {
1447 Debug.Write("CGDocumentManager.ViewRefresh Exception: " + ex.Message + "\n");
1448 }
1449 finally
1450 {
1451 }
1452 }
1453 Debug.Write("DocManager refreshed all views.\n");
1454 }
1455
1456 #endregion Methods & Events
1457
1458 }
1459}
Note: See TracBrowser for help on using the repository browser.