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
RevLine 
[1474]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
[614]7using System;
8using System.Windows.Forms;
9using System.Collections;
10using System.Data;
11using System.Diagnostics;
[1050]12using System.Threading;
[614]13using IndianHealthService.BMXNet;
[1474]14using IndianHealthService.BMXNet.WinForm;
15using IndianHealthService.BMXNet.WinForm.Configuration; //grrrr... too many namespaces here...
[772]16using Mono.Options;
[788]17using System.Runtime.InteropServices;
[1112]18using System.Globalization;
[614]19
20namespace IndianHealthService.ClinicalScheduling
21{
22 /// <summary>
[1050]23 /// Main Worker. Handles sub-forms.
[614]24 /// </summary>
[1050]25 public class CGDocumentManager //: System.Windows.Forms.Form
[614]26 {
27 #region Member Variables
28
29 private static CGDocumentManager _current;
[1050]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
[620]32 private string m_sWindowText = "Clinical Scheduling"; //Default Window Text
[1050]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
[824]36
[1050]37 //Connection variables (tied to command line parameters /a /v /s /p /e)
[1728]38 //New variables for ssh
[772]39 private string m_AccessCode="";
40 private string m_VerifyCode="";
41 private string m_Server="";
[1728]42 private string m_SshUser = "";
43 private string m_SshPassword = "";
[772]44 private int m_Port=0;
[1050]45 private string m_Encoding=""; //Encoding is "" by default;
[1728]46 public Process m_SsshProcess;
[614]47
[1112]48 //Globalization Object (tied to command line parameter /culture)
49 private string m_CultureName = "";
50
[843]51 //Data Access Layer
52 private DAL _dal = null;
53
[614]54 //M Connection member variables
[1050]55 private DataSet m_dsGlobal = null; // Holds all user data
[614]56
[1091]57 //Custom Printing
[1110]58 private Printing m_PrintingObject = null;
[614]59 #endregion
60
[1050]61 #region Properties
62
[1474]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
[1050]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 }
[1111]103
104 /// <summary>
[1112]105 /// User Preferences Auto Property
[1111]106 /// </summary>
107 public UserPreferences UserPreferences { get; private set; }
[1050]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
[1110]148 public Printing PrintingObject
[1091]149 {
150 get
151 {
152 return this.m_PrintingObject;
153 }
154 }
[1050]155 #endregion
156
157 /// <summary>
[1474]158 /// Private constructor for singleton instance.
[1050]159 /// </summary>
[1474]160 private CGDocumentManager()
[614]161 {
162 }
163
[1050]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)
[1112]180 /// /culture or -culture = Culture Name for UI Culture if you wish to override the Windows Culture
[1050]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.
[1095]185 /// - If that's not so, /e sets the default encoding. If /e is a non-existent encoding, move to next step.
[1050]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 {
[1122]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
[1050]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
[1065]203
204#if TRACE
205 DateTime startLoadTime = DateTime.Now;
206#endif
207
[1050]208 //Store a class instance of manager. Actual constructor does nothing.
209 _current = new CGDocumentManager();
210
[1071]211 //Get command line options; store in private class wide variables
[1050]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 },
[1112]217 { "e=", e => _current.m_Encoding = e},
[1728]218 { "su=",su => _current.m_SshUser = su },
219 { "sp=",sp => _current.m_SshPassword = sp },
[1112]220 { "culture=", culture => _current.m_CultureName = culture }
[1050]221 };
222
223 opset.Parse(args);
224
[1474]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 {
[1050]233
[1474]234 MessageBox.Show("Booboo: An Error Happened: " + ex.Message);
235 return; // exit application
236 }
237
238
239 //if something yucky happened, break out.
[1051]240 if (!isEverythingOkay) return;
241
[1050]242 //Create the first empty document
[1071]243 //A document holds the resources, appointments, and availabilites
[1070]244 //SAM: Good place for break point
[1050]245 CGDocument doc = new CGDocument();
246 doc.DocManager = _current;
[1071]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();
[1073]251 view.InitializeDocView(doc, _current, doc.StartDate, _current.WindowText);
[1071]252
[1474]253 //Handle Message Queue
[1050]254 Application.DoEvents();
[1071]255
[1122]256 //test
257 //doc.ThrowException();
258 //test
[1071]259
[1065]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
[1071]265
266 view.Show();
267 view.Activate();
268
[1050]269 Application.Run();
270 }
271
[1065]272 /// <summary>
[1122]273 /// Exception handler for application errors. Only for WinForm Errors.
[1065]274 /// </summary>
[1122]275 /// <remarks>Never tested. I can't get an error to go here!</remarks>
[1065]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
[1122]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;
[1065]304
[1122]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
[614]312 #region BMXNet Event Handler
[1474]313 private void CDocMgrEventHandler(Object obj, RemoteEventArgs e)
[614]314 {
[1474]315 if (e.EventType == "BSDX CALL WORKSTATIONS")
[614]316 {
317 string sParam = "";
318 string sDelim="~";
[1474]319 sParam += this.RemoteSession.User.Name + sDelim;
[614]320 sParam += this.m_sHandle + sDelim;
321 sParam += Application.ProductVersion + sDelim;
322 sParam += this._views.Count.ToString();
[1474]323 _current.RemoteSession.EventServices.TriggerEvent("BSDX WORKSTATION REPORT", sParam, true);
[614]324 }
[1474]325 if (e.EventType == "BSDX ADMIN MESSAGE")
[614]326 {
[1474]327 string sMsg = e.EventType;
[614]328 ShowAdminMsgDelegate samd = new ShowAdminMsgDelegate(ShowAdminMsg);
[1050]329 samd.Invoke(sMsg);
[614]330 }
[1474]331 if (e.EventType == "BSDX ADMIN SHUTDOWN")
[614]332 {
[1474]333 string sMsg = e.Details;
[614]334 CloseAllDelegate cad = new CloseAllDelegate(CloseAll);
[1050]335 cad.Invoke(sMsg);
[614]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
[1050]351 /// <summary>
352 /// See InitializeApp(bool) below
353 /// </summary>
[1051]354 private bool InitializeApp()
[614]355 {
[1051]356 return InitializeApp(false);
[614]357 }
358
[1050]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>
[1051]367 private bool InitializeApp(bool bReLogin)
[614]368 {
[1474]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();
[1050]378
[1474]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);
[1728]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 }
[1474]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;
[1728]434 if (m_SsshProcess != null)
435 {
436 spec.Server = "127.0.0.1";
437 }
[1474]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 {
[1728]472 if (m_SsshProcess != null)
473 {
474 if (!m_SsshProcess.HasExited)
475 {
476 m_SsshProcess.Kill();
477 }
478 }
[1474]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 {
[1728]486 if (m_SsshProcess != null)
487 {
488 if (!m_SsshProcess.HasExited)
489 {
490 m_SsshProcess.Kill();
491 }
492 }
[1474]493 return false;
494 }
495
496
497
498 this.RemoteSession = this.WinFramework.PrimaryRemoteSession;
499
[1050]500 //Tie delegate to Events generated by BMX.
[1474]501 this.RemoteSession.EventServices.RpmsEvent += this.CDocMgrEventHandler;
502 //Disable polling
503 this.RemoteSession.EventServices.IsEventPollingEnabled = false;
[824]504
[1474]505 //Second splash screens
[1051]506 //Show a splash screen while initializing; define delegates to remote thread
[1474]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);
[794]512
[1051]513 //Start new thread for the Splash screen.
[1070]514 Thread threadSplash = new Thread(new ParameterizedThreadStart(frm => ((DSplash)frm).ShowDialog()));
[1051]515 threadSplash.IsBackground = true; //expendable thread -- exit even if still running.
516 threadSplash.Name = "Splash Thread";
[1474]517 threadSplash.Start(secondSplash);
[794]518
[1474]519 firstSplash.Close(); // close temporary splash now that the new one is up and running
520
[1117]521 //There are 21 steps to load the application. That's max for the progress bar.
522 setMaxProgressDelegate(21);
[1474]523
[1051]524 // smh--not used: System.Configuration.ConfigurationManager.GetSection("appSettings");
[1050]525 setStatusDelegate("Connecting to VISTA");
[1474]526
[1051]527
[1474]528 /*
[1050]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.
[1051]533 //TODO: Make this more robust by sending a TCPConnect message and seeing if you get a response
[1050]534 if (m_Server != "" && m_Port != 0)
535 {
536 System.Net.Sockets.TcpClient tcpClient = new System.Net.Sockets.TcpClient();
537 try
[794]538 {
[1050]539 tcpClient.Connect(m_Server, m_Port); // open it
540 tcpClient.Close(); // then close it
541 }
[1051]542 catch (System.Net.Sockets.SocketException)
[1050]543 {
[1143]544 m_ds.RemoteMsgBox("Can't connect to server! Network Error");
[1051]545 return false;
[1050]546 }
547 }
548
[1062]549
550 bool bRetry = true;
551
[1051]552 // Do block is Log-in logic
553 do
[1050]554 {
555 // login crap
556 try
557 {
558 // Not my code
559 if (bReLogin == true)
[794]560 {
[1050]561 //Prompt for Access and Verify codes
562 _current.m_ConnectInfo.LoadConnectInfo("", "");
[794]563 }
[1050]564 // My code -- buts looks so ugly!
[1071]565 // Checks the passed parameters stored in the class variables
[1050]566 else
[794]567 {
[1050]568 if (m_Server != String.Empty && m_Port != 0 && m_AccessCode != String.Empty
569 && m_VerifyCode != String.Empty)
[794]570 {
[1050]571 m_ConnectInfo.LoadConnectInfo(m_Server, m_Port, m_AccessCode, m_VerifyCode);
[794]572 }
[1050]573 else if (m_Server != String.Empty && m_Port != 0)
574 m_ConnectInfo.LoadConnectInfo(m_Server, m_Port, "", "");
[794]575 else
[1050]576 m_ConnectInfo.LoadConnectInfo();
[794]577 }
[1050]578 bRetry = false;
579 }
580 catch (System.Net.Sockets.SocketException)
581 {
[1143]582 m_ds.RemoteMsgBox("Cannot connect to VistA. Network Error");
[1050]583 }
[1051]584 catch (BMXNetException ex)
[1050]585 {
[1143]586 if (m_ds.RemoteMsgBox("Unable to connect to VistA. " + ex.Message, "Clinical Scheduling", MessageBoxButtons.RetryCancel) == DialogResult.Retry)
[794]587 {
[1050]588 bRetry = true;
[1106]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 }
[794]597 }
[1050]598 else
[794]599 {
[1050]600 closeSplashDelegate();
601 bRetry = false;
[1051]602 return false; //tell main that it's a no go.
[794]603 }
[1050]604 }
605 }while (bRetry == true);
[1474]606 */
[1091]607
[1474]608 //Printing Custom DLL. Perfect place for code injection!!!
609 //*************************************************
[1098]610 string DllLocation = string.Empty;
[1091]611 System.IO.DirectoryInfo di = new System.IO.DirectoryInfo(Application.StartupPath + @"\Printing\");
[1098]612 if (di.Exists)
[1091]613 {
[1098]614 System.IO.FileInfo[] rgFiles = di.GetFiles("*.dll");
615
616 foreach (System.IO.FileInfo fi in rgFiles)
617 {
618 DllLocation = fi.FullName;
619 }
[1091]620 }
621
622 PrintingCreator Creator = null;
623 if (DllLocation == string.Empty)
624 {
[1110]625 this.m_PrintingObject = new Printing();
[1091]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 }
[1474]640 //************************************************
[1117]641
[1112]642 //User Interface Culture (m_CultureName is set from the command line flag /culture)
[1131]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 }
[1112]656
[1474]657 _dal = new DAL(RemoteSession); // Data access layer
658
[1050]659 //Create global dataset
660 _current.m_dsGlobal = new DataSet("GlobalDataSet");
[614]661
[1050]662 //Version info
[1051]663 // Table #1
664 setProgressDelegate(1);
[1050]665 setStatusDelegate("Getting Version Info from Server...");
[614]666
[1050]667 DataTable ver = _dal.GetVersion("BSDX");
668 ver.TableName = "VersionInfo";
669 m_dsGlobal.Tables.Add(ver);
[1039]670
[1050]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);
[614]679
[1050]680 //Make sure that the server is running the same version the client is.
681 Version x = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version;
[1039]682
[1050]683 //if version numbers mismatch, don't continue.
[1121]684 if (!(x.Major.ToString() == sMajor && x.Minor.ToString() == sMinor))
[1050]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");
[1121]691 closeSplashDelegate();
[1728]692 if (m_SsshProcess != null)
693 {
694 if (!m_SsshProcess.HasExited)
695 {
696 m_SsshProcess.Kill();
697 }
698 }
[1121]699 return false;
[1050]700 }
[1039]701
702
[1050]703 //Change encoding
[1051]704 // Call #2
705 setProgressDelegate(2);
[1050]706 setStatusDelegate("Setting encoding...");
[1474]707 //PORT TODO: Set encoding
[1050]708 if (m_Encoding == String.Empty)
709 {
[1474]710 string utf8_server_support = RemoteSession.TransmitRPC("BMX UTF-8", "");
711
[1050]712 if (utf8_server_support == "1")
[1474]713 RemoteSession.ConnectionEncoding = System.Text.UTF8Encoding.UTF8;
714
[1050]715 }
[1051]716
717 //Set application context
718 // Call #3
719 setProgressDelegate(3);
[1050]720 setStatusDelegate("Setting Application Context to BSDXRPC...");
[1474]721 RemoteSession.AppContext = "BSDXRPC";
[1117]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
[1474]727 _current.UserPreferences = new UserPreferences(); // Constructor Does the calling to do that...
[1117]728
729 //Load global recordsets
[1050]730 string statusConst = "Loading VistA data tables...";
731 setStatusDelegate(statusConst);
[614]732
[1050]733 string sCommandText;
[614]734
[1051]735 //Schedule User Info
736 // Table #4
[1117]737 setProgressDelegate(6);
[1050]738 setStatusDelegate(statusConst + " Schedule User");
[1474]739 DataTable dtUser = _dal.GetUserInfo(RemoteSession.User.Duz);
[1050]740 dtUser.TableName = "SchedulingUser";
741 m_dsGlobal.Tables.Add(dtUser);
742 Debug.Assert(dtUser.Rows.Count == 1);
[614]743
[1050]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;
[614]749
[1051]750 //Get Access Types
751 // Table #5
[1117]752 setProgressDelegate(7);
[1050]753 setStatusDelegate(statusConst + " Access Types");
[1474]754 DataTable dtAccessTypes = _dal.GetAccessTypes(m_dsGlobal, "AccessTypes");
[614]755
[1051]756 //Get Access Groups
757 // Table #6
[1117]758 setProgressDelegate(8);
[1050]759 setStatusDelegate(statusConst + " Access Groups");
760 LoadAccessGroupsTable();
[788]761
[1050]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
[1062]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.
[1051]772 // Table #7
[1117]773 setProgressDelegate(9);
[1050]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
[1051]790 //ResourceGroup Table (Resource Groups by User)
791 // Table #8
[1062]792 // What shows up on the tree. The groups the user has access to.
[1117]793 setProgressDelegate(10);
[1050]794 setStatusDelegate(statusConst + " Resource Groups By User");
795 LoadResourceGroupTable();
796
[1051]797 //Resources by user
798 // Table #9
[1062]799 // Individual Resources
[1117]800 setProgressDelegate(11);
[1050]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
[1051]809 //GroupResources table
810 // Table #10
[1062]811 // Resource Groups and Indivdual Resources together
[1117]812 setProgressDelegate(12);
[1050]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
[1095]825
[1050]826 m_dsGlobal.Relations.Add(dr);
827
[1051]828 //HospitalLocation table
829 //Table #11
[1117]830 setProgressDelegate(13);
[1050]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";
[1474]834 RemoteSession.TableFromCommand(sCommandText, m_dsGlobal, "HospitalLocation");
[1050]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
[1051]849 //Build ScheduleUser table
850 //Table #12
[1117]851 setProgressDelegate(14);
[1050]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
[1051]861 //Build ResourceUser table
862 //Table #13
[1062]863 //Acess to Resources by [this] User
[1117]864 setProgressDelegate(15);
[1050]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
[1051]880 //Build active provider table
881 //Table #14
[1062]882 //TODO: Lazy load the provider table; no need to load in advance.
[1117]883 setProgressDelegate(16);
[1050]884 setStatusDelegate(statusConst + " Providers");
885 sCommandText = "SELECT BMXIEN, NAME FROM NEW_PERSON WHERE INACTIVE_DATE = '' AND BMXIEN > 1";
[1474]886 RemoteSession.TableFromSQL(sCommandText, m_dsGlobal, "Provider");
[1050]887 Debug.Write("LoadGlobalRecordsets -- Provider loaded\n");
888
[1062]889 //Build the HOLIDAY table
[1051]890 //Table #15
[1117]891 setProgressDelegate(17);
[1050]892 setStatusDelegate(statusConst + " Holiday");
[1104]893 sCommandText = "SELECT NAME, DATE FROM HOLIDAY WHERE INTERNAL[DATE] > '" + FMDateTime.Create(DateTime.Today).DateOnly.FMDateString + "'";
[1474]894 RemoteSession.TableFromSQL(sCommandText, m_dsGlobal, "HOLIDAY");
[1050]895 Debug.Write("LoadingGlobalRecordsets -- Holidays loaded\n");
896
897
898 //Save the xml schema
899 //m_dsGlobal.WriteXmlSchema(@"..\..\csSchema20060526.xsd");
900 //----------------------------------------------
901
[1051]902 setStatusDelegate("Setting Receive Timeout");
[1474]903 _current.RemoteSession.ReceiveTimeout = 30000; //30-second timeout
[1050]904
[788]905#if DEBUG
[1474]906 _current.RemoteSession.ReceiveTimeout = 600000; //longer timeout for debugging
[1050]907#endif
[1051]908 // Event Subsriptions
909 setStatusDelegate("Subscribing to Server Events");
[1062]910 //Table #16
[1117]911 setProgressDelegate(18);
[1474]912 _current.RemoteSession.EventServices.Subscribe("BSDX SCHEDULE");
[1062]913 //Table #17
[1117]914 setProgressDelegate(19);
[1474]915 _current.RemoteSession.EventServices.Subscribe("BSDX CALL WORKSTATIONS");
[1051]916 //Table #18
[1117]917 setProgressDelegate(20);
[1474]918 _current.RemoteSession.EventServices.Subscribe("BSDX ADMIN MESSAGE");
[1051]919 //Table #19
[1117]920 setProgressDelegate(21);
[1474]921 _current.RemoteSession.EventServices.Subscribe("BSDX ADMIN SHUTDOWN");
[614]922
[1474]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
[614]928
[1050]929 //Close Splash Screen
930 closeSplashDelegate();
[1051]931
932 return true;
[1050]933
[614]934 }
935
936
[1050]937
[614]938 public void LoadAccessGroupsTable()
939 {
940 string sCommandText = "SELECT * FROM BSDX_ACCESS_GROUP";
[1474]941 RemoteSession.TableFromSQL(sCommandText, m_dsGlobal, "AccessGroup");
[614]942 Debug.Write("LoadGlobalRecordsets -- AccessGroups loaded\n");
943 }
944
945 public void LoadAccessGroupTypesTable()
946 {
947 string sCommandText = "BSDX GET ACCESS GROUP TYPES";
[1474]948 RemoteSession.TableFromCommand(sCommandText, m_dsGlobal, "AccessGroupType");
[614]949 Debug.Write("LoadGlobalRecordsets -- AccessGroupTypes loaded\n");
950 }
951
952 public void LoadBSDXResourcesTable()
953 {
[1474]954 string sCommandText = "BSDX RESOURCES^" + RemoteSession.User.Duz;
955 RemoteSession.TableFromCommand(sCommandText, m_dsGlobal, "Resources");
[614]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
[1474]965 string sCommandText = "BSDX RESOURCE GROUPS BY USER^" + RemoteSession.User.Duz;
966 RemoteSession.TableFromCommand(sCommandText, m_dsGlobal, "ResourceGroup");
[614]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
[1474]977 string sCommandText = "BSDX GROUP RESOURCE^" + RemoteSession.User.Duz;
978 RemoteSession.TableFromCommand(sCommandText, m_dsGlobal, "GroupResources");
[614]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";
[1474]987 RemoteSession.TableFromCommand(sCommandText, m_dsGlobal, "ScheduleUser");
[614]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 {
[1050]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 {
[1474]1006 sCommandText += String.Format(" WHERE INTERNAL[USERNAME] = {0}", RemoteSession.User.Duz);
[1050]1007 }
1008
[1474]1009 RemoteSession.TableFromSQL(sCommandText, m_dsGlobal, "ResourceUser");
[614]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
[1050]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>
[614]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 {
[1474]1124 RemoteSession.EventServices.IsEventPollingEnabled = false;
1125 RemoteSession.EventServices.Unsubscribe("BSDX SCHEDULE");
1126 RemoteSession.Close();
[614]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 {
[1474]1139 RemoteSession.Close();
[614]1140 Application.Exit();
1141 }
1142 }
1143
[1098]1144 /// <summary>
1145 /// Not used
1146 /// </summary>
[614]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
[1071]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>
[614]1263 private void mnuRPMSServer_Click(object sender, EventArgs e)
1264 {
1265 //Warn that changing servers will close all schedules
[627]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)
[614]1267 return;
1268
1269 //Reconnect to RPMS and recreate all global recordsets
1270 try
1271 {
[1071]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
[614]1274 m_bExitOK = false;
[1071]1275 CloseAll();
1276 m_bExitOK = true;
1277
1278 //Used in Do loop
[1474]1279 //bool bRetry = true;
[1071]1280
[1474]1281 /*// Do Loop to deal with changing the server and the vagaries of user choices.
[614]1282 do
1283 {
1284 try
1285 {
[1071]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
[1474]1290 LoginProcess login = this.WinFramework.CreateLoginProcess();
1291 login.AttemptUserInputLogin("ReLog-in", 3, true, null);
[614]1292 bRetry = false;
1293 }
1294 catch (Exception ex)
1295 {
1296 if (ex.Message == "User cancelled.")
1297 {
1298 bRetry = false;
[1071]1299 Application.Exit();
[614]1300 return;
1301 }
[627]1302 if (MessageBox.Show("Unable to connect to VistA. " + ex.Message , "Clinical Scheduling", MessageBoxButtons.RetryCancel) == DialogResult.Retry)
[614]1303 {
1304 bRetry = true;
1305 }
1306 else
1307 {
1308 bRetry = false;
[1071]1309 Application.Exit();
[614]1310 return;
1311 }
1312 }
1313 } while (bRetry == true);
[1474]1314 */
1315
[1071]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);
[614]1318
[1071]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 }
[614]1325
[1071]1326 //Otherwise, everything is okay. So open document and view, then show and activate view.
1327 CGDocument doc = new CGDocument();
1328 doc.DocManager = _current;
[614]1329
[1071]1330 CGView view = new CGView();
[1073]1331 view.InitializeDocView(doc, _current, doc.StartDate, _current.WindowText);
[1071]1332
1333 view.Show();
1334 view.Activate();
1335
1336 //Application.Run need not be called b/c it is already running.
[614]1337 }
1338 catch (Exception ex)
1339 {
1340 throw ex;
1341 }
1342
1343 }
1344
[1071]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>
[614]1350 private void mnuRPMSLogin_Click(object sender, EventArgs e)
1351 {
[1474]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
[627]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)
[614]1357 return;
1358
1359 //Reconnect to RPMS and recreate all global recordsets
1360 try
1361 {
[1071]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
[614]1364 m_bExitOK = false;
1365 CloseAll();
1366 m_bExitOK = true;
[1071]1367
[1474]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
[1071]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();
[1073]1401 view.InitializeDocView(doc, _current, doc.StartDate, _current.WindowText);
[1071]1402
1403 view.Show();
1404 view.Activate();
1405
1406 //Application.Run need not be called b/c it is already running.
[614]1407 }
1408 catch (Exception ex)
1409 {
1410 throw ex;
1411 }
[1474]1412 */
[614]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
[620]1424 MessageBox.Show(sMsg, "Clinical Scheduling Administrator -- System Shutdown Notification", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
[614]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
[1011]1458 public delegate DataTable RPMSDataTableDelegate(string CommandString, string TableName);
[614]1459
1460 public DataTable RPMSDataTable(string sSQL, string sTableName)
1461 {
1462 //Retrieves a recordset from RPMS
1463 string sErrorMessage = "";
[843]1464 DataTable dtOut;
1465
[614]1466 try
1467 {
[1011]1468 //System.IntPtr pHandle = this.Handle;
[1474]1469 RPMSDataTableDelegate rdtd = new RPMSDataTableDelegate(RemoteSession.TableFromCommand);
[1050]1470 //dtOut = (DataTable) this.Invoke(rdtd, new object[] {sSQL, sTableName});
[1474]1471 dtOut = RemoteSession.TableFromCommand(sSQL);
1472 dtOut.TableName = sTableName;
1473
[614]1474 }
[843]1475
[614]1476 catch (Exception ex)
1477 {
1478 sErrorMessage = "CGDocumentManager.RPMSDataTable error: " + ex.Message;
1479 throw ex;
1480 }
[843]1481
1482 return dtOut;
1483
[614]1484 }
1485
1486 public void ChangeDivision(System.Windows.Forms.Form frmCaller)
1487 {
[1474]1488 WinFramework.AttemptUserInputSetDivision("Change Division", frmCaller);
1489
1490 RemoteSession = WinFramework.PrimaryRemoteSession;
1491
[614]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.