source: Scheduling/trunk/cs/bsdx0200GUISourceCode/CGDocumentManager.cs@ 1728

Last change on this file since 1728 was 1728, checked in by Faisal Sami, 8 years ago

ClinicalScheduling version 2.0.

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