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

Last change on this file since 1742 was 1731, checked in by Faisal Sami, 9 years ago

BSDX Scheduling changes for version 2.0.1.

File size: 56.1 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";
[1731]392
[1728]393 if (System.IO.File.Exists(path))
394 {
395 string prms = "-ssh -l " + m_SshUser + " -pw " + m_SshPassword + " -L " + m_Port + ":127.0.0.1:" + m_Port + " " + m_Server;
396 //m_SsshProcess = System.Diagnostics.Process.Start(path, prms);
397 ProcessStartInfo si = new ProcessStartInfo(path, prms);
398 si.WindowStyle = ProcessWindowStyle.Minimized;
399 m_SsshProcess = Process.Start(si);
400 }
401 }
[1474]402
403 if (bReLogin) // if logging in again...
404 {
405 this.WinFramework.LoadConnectionSpecs(LocalPersistentStore.CreateDefaultStorage(true), "BSDX");
406 login = this.WinFramework.CreateLoginProcess();
407 login.AttemptUserInputLogin("Clincal Scheduling Log-in", 3, true, firstSplash);
408 goto DoneTrying;
409 }
410
411 // If server,port,ac,vc are supplied on command line, then try to connect...
412 else if (!String.IsNullOrEmpty(m_Server) && m_Port != 0 && !String.IsNullOrEmpty(m_AccessCode) && !String.IsNullOrEmpty(m_VerifyCode))
413 {
414 RpmsConnectionSpec spec = new RpmsConnectionSpec();
415 spec.IsDefault = true;
416 spec.Name = "Command Line Server";
417 spec.Port = m_Port;
418 spec.Server = m_Server;
419 spec.UseWindowsAuthentication = false; //for now
420 spec.UseDefaultNamespace = true; //for now
421 login = this.WinFramework.CreateLoginProcess();
422 login.AutoSetDivisionToLastLookup = false;
423 login.AttemptAccessVerifyLogin(spec, m_AccessCode, m_VerifyCode);
424 goto DoneTrying;
425 }
426
427 // if only server, port is supplied, then use these instead
428 else if (!String.IsNullOrEmpty(m_Server) && m_Port != 0)
429 {
430 RpmsConnectionSpec spec = new RpmsConnectionSpec();
431 spec.IsDefault = true;
432 spec.Name = "Command Line Server";
433 spec.Port = m_Port;
434 spec.Server = m_Server;
[1728]435 if (m_SsshProcess != null)
436 {
437 spec.Server = "127.0.0.1";
438 }
[1474]439 spec.UseWindowsAuthentication = false; //for now
440 spec.UseDefaultNamespace = true; //for now
441
442 RpmsConnectionSettings cxnSettings = new RpmsConnectionSettings
443 {
444 CommandLineConnectionSpec = spec
445 };
446
447 this.WinFramework.ConnectionSettings = cxnSettings;
448
449 login = this.WinFramework.CreateLoginProcess();
450 login.AutoSetDivisionToLastLookup = false;
451 //test
452 //spec.UseWindowsAuthentication = true;
453 login.AttemptUserInputLogin("Clinical Scheduling Log-in", 3, false, firstSplash);
454 //login.AttemptWindowsAuthLogin();
455 //test
456 goto DoneTrying;
457 }
458
459 // if nothing is supplied, fall back on the original dialog
460 else
461 {
462 this.WinFramework.LoadConnectionSpecs(LocalPersistentStore.CreateDefaultStorage(true), "BSDX");
463 login = this.WinFramework.CreateLoginProcess();
464 login.AutoSetDivisionToLastLookup = false;
465 login.AttemptUserInputLogin("Clincal Scheduling Log-in", 3, true, firstSplash);
466
467 goto DoneTrying;
468 }
469
470DoneTrying:
471 if (!login.WasSuccessful)
472 {
[1728]473 if (m_SsshProcess != null)
474 {
475 if (!m_SsshProcess.HasExited)
476 {
477 m_SsshProcess.Kill();
478 }
479 }
[1474]480 return false;
481 }
482
483 LocalSession local = this.WinFramework.LocalSession;
484
485 if ((this.WinFramework.Context.User.Division == null) && !this.WinFramework.AttemptUserInputSetDivision("Set Initial Division", firstSplash))
486 {
[1728]487 if (m_SsshProcess != null)
488 {
489 if (!m_SsshProcess.HasExited)
490 {
491 m_SsshProcess.Kill();
492 }
493 }
[1474]494 return false;
495 }
496
497
498
499 this.RemoteSession = this.WinFramework.PrimaryRemoteSession;
500
[1050]501 //Tie delegate to Events generated by BMX.
[1474]502 this.RemoteSession.EventServices.RpmsEvent += this.CDocMgrEventHandler;
503 //Disable polling
504 this.RemoteSession.EventServices.IsEventPollingEnabled = false;
[824]505
[1474]506 //Second splash screens
[1051]507 //Show a splash screen while initializing; define delegates to remote thread
[1474]508 DSplash secondSplash = new DSplash();
509 DSplash.dSetStatus setStatusDelegate = new DSplash.dSetStatus(secondSplash.SetStatus);
510 DSplash.dAny closeSplashDelegate = new DSplash.dAny(secondSplash.RemoteClose);
511 DSplash.dProgressBarSet setMaxProgressDelegate = new DSplash.dProgressBarSet(secondSplash.RemoteProgressBarMaxSet);
512 DSplash.dProgressBarSet setProgressDelegate = new DSplash.dProgressBarSet(secondSplash.RemoteProgressBarValueSet);
[794]513
[1051]514 //Start new thread for the Splash screen.
[1070]515 Thread threadSplash = new Thread(new ParameterizedThreadStart(frm => ((DSplash)frm).ShowDialog()));
[1051]516 threadSplash.IsBackground = true; //expendable thread -- exit even if still running.
517 threadSplash.Name = "Splash Thread";
[1474]518 threadSplash.Start(secondSplash);
[794]519
[1474]520 firstSplash.Close(); // close temporary splash now that the new one is up and running
521
[1117]522 //There are 21 steps to load the application. That's max for the progress bar.
523 setMaxProgressDelegate(21);
[1474]524
[1051]525 // smh--not used: System.Configuration.ConfigurationManager.GetSection("appSettings");
[1050]526 setStatusDelegate("Connecting to VISTA");
[1474]527
[1051]528
[1474]529 /*
[1050]530 //Try to connect using supplied values for Server and Port
531 //Why am I doing this? The library BMX net uses prompts for access and verify code
532 //whether you can connect or not. Not good. So I test first whether
533 //we can connect at all by doing a simple connection and disconnect.
[1051]534 //TODO: Make this more robust by sending a TCPConnect message and seeing if you get a response
[1050]535 if (m_Server != "" && m_Port != 0)
536 {
537 System.Net.Sockets.TcpClient tcpClient = new System.Net.Sockets.TcpClient();
538 try
[794]539 {
[1050]540 tcpClient.Connect(m_Server, m_Port); // open it
541 tcpClient.Close(); // then close it
542 }
[1051]543 catch (System.Net.Sockets.SocketException)
[1050]544 {
[1143]545 m_ds.RemoteMsgBox("Can't connect to server! Network Error");
[1051]546 return false;
[1050]547 }
548 }
549
[1062]550
551 bool bRetry = true;
552
[1051]553 // Do block is Log-in logic
554 do
[1050]555 {
556 // login crap
557 try
558 {
559 // Not my code
560 if (bReLogin == true)
[794]561 {
[1050]562 //Prompt for Access and Verify codes
563 _current.m_ConnectInfo.LoadConnectInfo("", "");
[794]564 }
[1050]565 // My code -- buts looks so ugly!
[1071]566 // Checks the passed parameters stored in the class variables
[1050]567 else
[794]568 {
[1050]569 if (m_Server != String.Empty && m_Port != 0 && m_AccessCode != String.Empty
570 && m_VerifyCode != String.Empty)
[794]571 {
[1050]572 m_ConnectInfo.LoadConnectInfo(m_Server, m_Port, m_AccessCode, m_VerifyCode);
[794]573 }
[1050]574 else if (m_Server != String.Empty && m_Port != 0)
575 m_ConnectInfo.LoadConnectInfo(m_Server, m_Port, "", "");
[794]576 else
[1050]577 m_ConnectInfo.LoadConnectInfo();
[794]578 }
[1050]579 bRetry = false;
580 }
581 catch (System.Net.Sockets.SocketException)
582 {
[1143]583 m_ds.RemoteMsgBox("Cannot connect to VistA. Network Error");
[1050]584 }
[1051]585 catch (BMXNetException ex)
[1050]586 {
[1143]587 if (m_ds.RemoteMsgBox("Unable to connect to VistA. " + ex.Message, "Clinical Scheduling", MessageBoxButtons.RetryCancel) == DialogResult.Retry)
[794]588 {
[1050]589 bRetry = true;
[1106]590 //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.
591 try { _current.m_ConnectInfo.ChangeServerInfo(); }
592 catch (Exception)
593 {
594 closeSplashDelegate();
595 bRetry = false;
596 return false; //tell main that it's a no go.
597 }
[794]598 }
[1050]599 else
[794]600 {
[1050]601 closeSplashDelegate();
602 bRetry = false;
[1051]603 return false; //tell main that it's a no go.
[794]604 }
[1050]605 }
606 }while (bRetry == true);
[1474]607 */
[1091]608
[1474]609 //Printing Custom DLL. Perfect place for code injection!!!
610 //*************************************************
[1098]611 string DllLocation = string.Empty;
[1091]612 System.IO.DirectoryInfo di = new System.IO.DirectoryInfo(Application.StartupPath + @"\Printing\");
[1098]613 if (di.Exists)
[1091]614 {
[1098]615 System.IO.FileInfo[] rgFiles = di.GetFiles("*.dll");
616
617 foreach (System.IO.FileInfo fi in rgFiles)
618 {
619 DllLocation = fi.FullName;
620 }
[1091]621 }
622
623 PrintingCreator Creator = null;
624 if (DllLocation == string.Empty)
625 {
[1110]626 this.m_PrintingObject = new Printing();
[1091]627 }
628 else
629 {
630 System.Reflection.Assembly assembly = System.Reflection.Assembly.LoadFrom(DllLocation);
631 foreach (Type type in assembly.GetTypes())
632 {
633 if (type.IsClass == true & type.BaseType == typeof(PrintingCreator))
634 {
635 Creator = (PrintingCreator)Activator.CreateInstance(type);
636 break;
637 }
638 }
639 this.m_PrintingObject = Creator.PrintFactory();
640 }
[1474]641 //************************************************
[1117]642
[1112]643 //User Interface Culture (m_CultureName is set from the command line flag /culture)
[1131]644 //
645 //If passed, set that try that culture; fail over to Invariant Culture
646 if (m_CultureName != String.Empty)
647 {
648 try { Thread.CurrentThread.CurrentUICulture = new CultureInfo(m_CultureName); }
649 catch (CultureNotFoundException) { Thread.CurrentThread.CurrentUICulture = CultureInfo.InvariantCulture; }
650 }
651 //otherwise, use the Current Computer Culture, EVEN IF (!!) the UI Culture is different.
652 //this allows localization even if Windows still displays messages in English.
653 else
654 {
655 Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture;
656 }
[1112]657
[1474]658 _dal = new DAL(RemoteSession); // Data access layer
659
[1050]660 //Create global dataset
661 _current.m_dsGlobal = new DataSet("GlobalDataSet");
[614]662
[1050]663 //Version info
[1051]664 // Table #1
665 setProgressDelegate(1);
[1050]666 setStatusDelegate("Getting Version Info from Server...");
[614]667
[1050]668 DataTable ver = _dal.GetVersion("BSDX");
669 ver.TableName = "VersionInfo";
670 m_dsGlobal.Tables.Add(ver);
[1039]671
[1050]672 //How to extract the version numbers:
673 DataTable dtVersion = m_dsGlobal.Tables["VersionInfo"];
674 Debug.Assert(dtVersion.Rows.Count == 1);
675 DataRow rVersion = dtVersion.Rows[0];
676 string sMajor = rVersion["MAJOR_VERSION"].ToString();
677 string sMinor = rVersion["MINOR_VERSION"].ToString();
678 string sBuild = rVersion["BUILD"].ToString();
679 decimal fBuild = Convert.ToDecimal(sBuild);
[614]680
[1050]681 //Make sure that the server is running the same version the client is.
682 Version x = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version;
[1039]683
[1050]684 //if version numbers mismatch, don't continue.
[1121]685 if (!(x.Major.ToString() == sMajor && x.Minor.ToString() == sMinor))
[1050]686 {
687 MessageBox.Show(
688 "Server runs version " + sMajor + "." + sMinor + "\r\n" +
689 "You are running " + x.ToString() + "\r\n\r\n" +
690 "Major, Minor and Build versions must match",
691 "Version Mismatch");
[1121]692 closeSplashDelegate();
[1728]693 if (m_SsshProcess != null)
694 {
695 if (!m_SsshProcess.HasExited)
696 {
697 m_SsshProcess.Kill();
698 }
699 }
[1121]700 return false;
[1050]701 }
[1039]702
703
[1050]704 //Change encoding
[1051]705 // Call #2
706 setProgressDelegate(2);
[1050]707 setStatusDelegate("Setting encoding...");
[1474]708 //PORT TODO: Set encoding
[1050]709 if (m_Encoding == String.Empty)
710 {
[1474]711 string utf8_server_support = RemoteSession.TransmitRPC("BMX UTF-8", "");
712
[1050]713 if (utf8_server_support == "1")
[1474]714 RemoteSession.ConnectionEncoding = System.Text.UTF8Encoding.UTF8;
715
[1050]716 }
[1051]717
718 //Set application context
719 // Call #3
720 setProgressDelegate(3);
[1050]721 setStatusDelegate("Setting Application Context to BSDXRPC...");
[1474]722 RemoteSession.AppContext = "BSDXRPC";
[1117]723
724 //User Preferences Object
725 setProgressDelegate(4); //next number is 6 b/c two calls
726 setStatusDelegate("Getting User Preferences from the Server...");
727
[1474]728 _current.UserPreferences = new UserPreferences(); // Constructor Does the calling to do that...
[1117]729
730 //Load global recordsets
[1050]731 string statusConst = "Loading VistA data tables...";
732 setStatusDelegate(statusConst);
[614]733
[1050]734 string sCommandText;
[614]735
[1051]736 //Schedule User Info
737 // Table #4
[1117]738 setProgressDelegate(6);
[1050]739 setStatusDelegate(statusConst + " Schedule User");
[1474]740 DataTable dtUser = _dal.GetUserInfo(RemoteSession.User.Duz);
[1050]741 dtUser.TableName = "SchedulingUser";
742 m_dsGlobal.Tables.Add(dtUser);
743 Debug.Assert(dtUser.Rows.Count == 1);
[614]744
[1050]745 // Only one row and one column named "MANAGER". Set local var m_bSchedManager to true if Manager.
746 DataRow rUser = dtUser.Rows[0];
747 Object oUser = rUser["MANAGER"];
748 string sUser = oUser.ToString();
749 m_bSchedManager = (sUser == "YES") ? true : false;
[614]750
[1051]751 //Get Access Types
752 // Table #5
[1117]753 setProgressDelegate(7);
[1050]754 setStatusDelegate(statusConst + " Access Types");
[1474]755 DataTable dtAccessTypes = _dal.GetAccessTypes(m_dsGlobal, "AccessTypes");
[614]756
[1051]757 //Get Access Groups
758 // Table #6
[1117]759 setProgressDelegate(8);
[1050]760 setStatusDelegate(statusConst + " Access Groups");
761 LoadAccessGroupsTable();
[788]762
[1050]763 //Build Primary Key for AccessGroup table
764 DataTable dtGroups = m_dsGlobal.Tables["AccessGroup"];
765 DataColumn dcKey = dtGroups.Columns["ACCESS_GROUP"];
766 DataColumn[] dcKeys = new DataColumn[1];
767 dcKeys[0] = dcKey;
768 dtGroups.PrimaryKey = dcKeys;
769
[1062]770 //Get Access Group Types (Combines Access Types and Groups)
771 //Optimization Note: Can eliminate Access type and Access Group Table
772 // But they are heavily referenced throughout the code.
[1051]773 // Table #7
[1117]774 setProgressDelegate(9);
[1050]775 setStatusDelegate(statusConst + " Access Group Types");
776 LoadAccessGroupTypesTable();
777
778 //Build Primary Key for AccessGroupType table
779 DataTable dtAGTypes = m_dsGlobal.Tables["AccessGroupType"];
780 DataColumn dcGTKey = dtAGTypes.Columns["ACCESS_GROUP_TYPEID"];
781 DataColumn[] dcGTKeys = new DataColumn[1];
782 dcGTKeys[0] = dcGTKey;
783 dtAGTypes.PrimaryKey = dcGTKeys;
784
785 //Build Data Relationship between AccessGroupType and AccessTypes tables
786 DataRelation dr = new DataRelation("AccessGroupType", //Relation Name
787 m_dsGlobal.Tables["AccessGroup"].Columns["BMXIEN"], //Parent
788 m_dsGlobal.Tables["AccessGroupType"].Columns["ACCESS_GROUP_ID"]); //Child
789 m_dsGlobal.Relations.Add(dr);
790
[1051]791 //ResourceGroup Table (Resource Groups by User)
792 // Table #8
[1062]793 // What shows up on the tree. The groups the user has access to.
[1117]794 setProgressDelegate(10);
[1050]795 setStatusDelegate(statusConst + " Resource Groups By User");
796 LoadResourceGroupTable();
797
[1051]798 //Resources by user
799 // Table #9
[1062]800 // Individual Resources
[1117]801 setProgressDelegate(11);
[1050]802 setStatusDelegate(statusConst + " Resources By User");
803 LoadBSDXResourcesTable();
804
805 //Build Primary Key for Resources table
806 DataColumn[] dc = new DataColumn[1];
807 dc[0] = m_dsGlobal.Tables["Resources"].Columns["RESOURCEID"];
808 m_dsGlobal.Tables["Resources"].PrimaryKey = dc;
809
[1051]810 //GroupResources table
811 // Table #10
[1062]812 // Resource Groups and Indivdual Resources together
[1117]813 setProgressDelegate(12);
[1050]814 setStatusDelegate(statusConst + " Group Resources");
815 LoadGroupResourcesTable();
816
817 //Build Primary Key for ResourceGroup table
818 dc = new DataColumn[1];
819 dc[0] = m_dsGlobal.Tables["ResourceGroup"].Columns["RESOURCE_GROUP"];
820 m_dsGlobal.Tables["ResourceGroup"].PrimaryKey = dc;
821
822 //Build Data Relationships between ResourceGroup and GroupResources tables
823 dr = new DataRelation("GroupResource", //Relation Name
824 m_dsGlobal.Tables["ResourceGroup"].Columns["RESOURCE_GROUP"], //Parent
825 m_dsGlobal.Tables["GroupResources"].Columns["RESOURCE_GROUP"]); //Child
[1095]826
[1050]827 m_dsGlobal.Relations.Add(dr);
828
[1051]829 //HospitalLocation table
830 //Table #11
[1117]831 setProgressDelegate(13);
[1050]832 setStatusDelegate(statusConst + " Clinics");
833 //cmd.CommandText = "SELECT BMXIEN 'HOSPITAL_LOCATION_ID', NAME 'HOSPITAL_LOCATION', DEFAULT_PROVIDER, STOP_CODE_NUMBER, INACTIVATE_DATE, REACTIVATE_DATE FROM HOSPITAL_LOCATION";
834 sCommandText = "BSDX HOSPITAL LOCATION";
[1474]835 RemoteSession.TableFromCommand(sCommandText, m_dsGlobal, "HospitalLocation");
[1050]836 Debug.Write("LoadGlobalRecordsets -- HospitalLocation loaded\n");
837
838 //Build Primary Key for HospitalLocation table
839 dc = new DataColumn[1];
840 DataTable dtTemp = m_dsGlobal.Tables["HospitalLocation"];
841 dc[0] = dtTemp.Columns["HOSPITAL_LOCATION_ID"];
842 m_dsGlobal.Tables["HospitalLocation"].PrimaryKey = dc;
843
844 //Build Data Relationships between Resources and HospitalLocation tables
845 dr = new DataRelation("HospitalLocationResource", //Relation Name
846 m_dsGlobal.Tables["HospitalLocation"].Columns["HOSPITAL_LOCATION_ID"], //Parent
847 m_dsGlobal.Tables["Resources"].Columns["HOSPITAL_LOCATION_ID"], false); //Child
848 m_dsGlobal.Relations.Add(dr);
849
[1051]850 //Build ScheduleUser table
851 //Table #12
[1117]852 setProgressDelegate(14);
[1050]853 setStatusDelegate(statusConst + " Schedule User");
854 this.LoadScheduleUserTable();
855
856 //Build Primary Key for ScheduleUser table
857 dc = new DataColumn[1];
858 dtTemp = m_dsGlobal.Tables["ScheduleUser"];
859 dc[0] = dtTemp.Columns["USERID"];
860 m_dsGlobal.Tables["ScheduleUser"].PrimaryKey = dc;
861
[1051]862 //Build ResourceUser table
863 //Table #13
[1062]864 //Acess to Resources by [this] User
[1117]865 setProgressDelegate(15);
[1050]866 setStatusDelegate(statusConst + " Resource User");
867 this.LoadResourceUserTable();
868
869 //Build Primary Key for ResourceUser table
870 dc = new DataColumn[1];
871 dtTemp = m_dsGlobal.Tables["ResourceUser"];
872 dc[0] = dtTemp.Columns["RESOURCEUSER_ID"];
873 m_dsGlobal.Tables["ResourceUser"].PrimaryKey = dc;
874
875 //Create relation between BSDX Resource and BSDX Resource User tables
876 dr = new DataRelation("ResourceUser", //Relation Name
877 m_dsGlobal.Tables["Resources"].Columns["RESOURCEID"], //Parent
878 m_dsGlobal.Tables["ResourceUser"].Columns["RESOURCEID"]); //Child
879 m_dsGlobal.Relations.Add(dr);
880
[1051]881 //Build active provider table
882 //Table #14
[1062]883 //TODO: Lazy load the provider table; no need to load in advance.
[1117]884 setProgressDelegate(16);
[1050]885 setStatusDelegate(statusConst + " Providers");
886 sCommandText = "SELECT BMXIEN, NAME FROM NEW_PERSON WHERE INACTIVE_DATE = '' AND BMXIEN > 1";
[1474]887 RemoteSession.TableFromSQL(sCommandText, m_dsGlobal, "Provider");
[1050]888 Debug.Write("LoadGlobalRecordsets -- Provider loaded\n");
889
[1062]890 //Build the HOLIDAY table
[1051]891 //Table #15
[1117]892 setProgressDelegate(17);
[1050]893 setStatusDelegate(statusConst + " Holiday");
[1104]894 sCommandText = "SELECT NAME, DATE FROM HOLIDAY WHERE INTERNAL[DATE] > '" + FMDateTime.Create(DateTime.Today).DateOnly.FMDateString + "'";
[1474]895 RemoteSession.TableFromSQL(sCommandText, m_dsGlobal, "HOLIDAY");
[1050]896 Debug.Write("LoadingGlobalRecordsets -- Holidays loaded\n");
897
898
899 //Save the xml schema
900 //m_dsGlobal.WriteXmlSchema(@"..\..\csSchema20060526.xsd");
901 //----------------------------------------------
902
[1051]903 setStatusDelegate("Setting Receive Timeout");
[1474]904 _current.RemoteSession.ReceiveTimeout = 30000; //30-second timeout
[1050]905
[788]906#if DEBUG
[1474]907 _current.RemoteSession.ReceiveTimeout = 600000; //longer timeout for debugging
[1050]908#endif
[1051]909 // Event Subsriptions
910 setStatusDelegate("Subscribing to Server Events");
[1062]911 //Table #16
[1117]912 setProgressDelegate(18);
[1474]913 _current.RemoteSession.EventServices.Subscribe("BSDX SCHEDULE");
[1062]914 //Table #17
[1117]915 setProgressDelegate(19);
[1474]916 _current.RemoteSession.EventServices.Subscribe("BSDX CALL WORKSTATIONS");
[1051]917 //Table #18
[1117]918 setProgressDelegate(20);
[1474]919 _current.RemoteSession.EventServices.Subscribe("BSDX ADMIN MESSAGE");
[1051]920 //Table #19
[1117]921 setProgressDelegate(21);
[1474]922 _current.RemoteSession.EventServices.Subscribe("BSDX ADMIN SHUTDOWN");
[1731]923
924 string result = _current.RemoteSession.TransmitRPC("VEFA GET BMX POLL INTERVAL","");
925 bool eventPoolEnabled = false;
926 if (result.Split('^')[0] == "1")
927 {
928 eventPoolEnabled = true;
929 }
930 int eventPoolInterval = Convert.ToInt32(result.Split('^')[1]);
931 _current.RemoteSession.EventServices.EventPollingInterval = (eventPoolInterval * 1000); //in milliseconds
932 _current.RemoteSession.EventServices.IsEventPollingEnabled = eventPoolEnabled;
[1474]933
934 //PORT TODO: No Autofire in BMX 4.0
935 //_current.RemoteSession.EventServices. = 12; //AutoFire every 12*5 seconds
[614]936
[1050]937 //Close Splash Screen
938 closeSplashDelegate();
[1051]939
940 return true;
[1050]941
[614]942 }
943
944
[1050]945
[614]946 public void LoadAccessGroupsTable()
947 {
948 string sCommandText = "SELECT * FROM BSDX_ACCESS_GROUP";
[1474]949 RemoteSession.TableFromSQL(sCommandText, m_dsGlobal, "AccessGroup");
[614]950 Debug.Write("LoadGlobalRecordsets -- AccessGroups loaded\n");
951 }
952
953 public void LoadAccessGroupTypesTable()
954 {
955 string sCommandText = "BSDX GET ACCESS GROUP TYPES";
[1474]956 RemoteSession.TableFromCommand(sCommandText, m_dsGlobal, "AccessGroupType");
[614]957 Debug.Write("LoadGlobalRecordsets -- AccessGroupTypes loaded\n");
958 }
959
960 public void LoadBSDXResourcesTable()
961 {
[1474]962 string sCommandText = "BSDX RESOURCES^" + RemoteSession.User.Duz;
963 RemoteSession.TableFromCommand(sCommandText, m_dsGlobal, "Resources");
[614]964 Debug.Write("LoadGlobalRecordsets -- Resources loaded\n");
965 }
966
967 public void LoadResourceGroupTable()
968 {
969 //ResourceGroup Table (Resource Groups by User)
970 //Table "ResourceGroup" contains all resource group names
971 //to which user has access
972 //Fields are: RESOURCE_GROUPID, RESOURCE_GROUP
[1474]973 string sCommandText = "BSDX RESOURCE GROUPS BY USER^" + RemoteSession.User.Duz;
974 RemoteSession.TableFromCommand(sCommandText, m_dsGlobal, "ResourceGroup");
[614]975 Debug.Write("LoadGlobalRecordsets -- ResourceGroup loaded\n");
976 }
977
978 public void LoadGroupResourcesTable()
979 {
980 //Table "GroupResources" contains all active GROUP/RESOURCE combinations
981 //to which user has access based on entries in BSDX RESOURCE USER file
982 //If user has BSDXZMGR or XUPROGMODE keys, then ALL Group/Resource combinstions
983 //are returned.
984 //Fields are: RESOURCE_GROUPID, RESOURCE_GROUP, RESOURCE_GROUP_ITEMID, RESOURCE_NAME, RESOURCE_ID
[1474]985 string sCommandText = "BSDX GROUP RESOURCE^" + RemoteSession.User.Duz;
986 RemoteSession.TableFromCommand(sCommandText, m_dsGlobal, "GroupResources");
[614]987 Debug.Write("LoadGlobalRecordsets -- GroupResources loaded\n");
988 }
989
990 public void LoadScheduleUserTable()
991 {
992 //Table "ScheduleUser" contains an entry for each user in File 200 (NEW PERSON)
993 //who possesses the BSDXZMENU security key.
994 string sCommandText = "BSDX SCHEDULE USER";
[1474]995 RemoteSession.TableFromCommand(sCommandText, m_dsGlobal, "ScheduleUser");
[614]996 Debug.Write("LoadGlobalRecordsets -- ScheduleUser loaded\n");
997 }
998
999 public void LoadResourceUserTable()
1000 {
1001 //Table "ResourceUser" duplicates the BSDX RESOURCE USER File.
1002 //NOTE: Column names are RESOURCEUSER_ID, RESOURCEID,
1003 // OVERBOOK, MODIFY_SCHEDULE, USERID, USERID1
1004 //string sCommandText = "SELECT BMXIEN RESOURCEUSER_ID, INTERNAL[RESOURCENAME] RESOURCEID, OVERBOOK, MODIFY_SCHEDULE, USERNAME USERID, INTERNAL[USERNAME] FROM BSDX_RESOURCE_USER";
1005 LoadResourceUserTable(false);
1006 }
1007
1008 public void LoadResourceUserTable(bool bAllUsers)
1009 {
[1050]1010 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;
1011
1012 if (!bAllUsers)
1013 {
[1474]1014 sCommandText += String.Format(" WHERE INTERNAL[USERNAME] = {0}", RemoteSession.User.Duz);
[1050]1015 }
1016
[1474]1017 RemoteSession.TableFromSQL(sCommandText, m_dsGlobal, "ResourceUser");
[614]1018 Debug.Write("LoadGlobalRecordsets -- ResourceUser loaded\n");
1019 }
1020
1021
1022 public void RegisterDocumentView(CGDocument doc, CGView view)
1023 {
1024 //Store the view in the list of views
1025 this.Views.Add(view, doc);
1026
1027 //Hook into the view's 'closed' event
1028 view.Closed += new EventHandler(ViewClosed);
1029
1030 //Hook into the view's mnuRPMSServer.Click event
1031 view.mnuRPMSServer.Click += new EventHandler(mnuRPMSServer_Click);
1032
1033 //Hook into the view's mnuRPMSLogin.Click event
1034 view.mnuRPMSLogin.Click += new EventHandler(mnuRPMSLogin_Click);
1035
1036 }
1037
1038 public void RegisterAVDocumentView(CGAVDocument doc, CGAVView view)
1039 {
1040 //Store the view in the list of views
1041 this.AvailabilityViews.Add(view, doc);
1042
1043 //Hook into the view's 'closed' event
1044 view.Closed += new EventHandler(AVViewClosed);
1045 }
1046
1047 public CGAVView GetAVViewByResource(ArrayList sResourceArray)
1048 {
1049 if (sResourceArray == null)
1050 return null;
1051
1052 bool bEqual = true;
1053 foreach (CGAVView v in m_AVViews.Keys)
1054 {
1055 CGAVDocument d = v.Document;
1056
1057 bEqual = false;
1058 if (d.Resources.Count == sResourceArray.Count)
1059 {
1060 bEqual = true;
1061 for (int j = 0; j < sResourceArray.Count; j++)
1062 {
1063 if (sResourceArray.Contains(d.Resources[j]) == false)
1064 {
1065 bEqual = false;
1066 break;
1067 }
1068 if (d.Resources.Contains(sResourceArray[j]) == false)
1069 {
1070 bEqual = false;
1071 break;
1072 }
1073 }
1074 if (bEqual == true)
1075 return v;
1076 }
1077 }
1078 return null;
1079 }
1080 /// <summary>
1081 /// Return the first view having a resource array matching sResourceArray
1082 /// </summary>
1083 /// <param name="sResourceArray"></param>
1084 /// <returns></returns>
1085 public CGView GetViewByResource(ArrayList sResourceArray)
1086 {
1087 if (sResourceArray == null)
1088 return null;
1089
1090 bool bEqual = true;
1091 foreach (CGView v in _views.Keys)
1092 {
1093 CGDocument d = v.Document;
1094
1095 bEqual = false;
1096 if (d.Resources.Count == sResourceArray.Count)
1097 {
1098 bEqual = true;
1099 for (int j = 0; j < sResourceArray.Count; j++)
1100 {
1101 if (sResourceArray.Contains(d.Resources[j]) == false)
1102 {
1103 bEqual = false;
1104 break;
1105 }
1106 if (d.Resources.Contains(sResourceArray[j]) == false)
1107 {
1108 bEqual = false;
1109 break;
1110 }
1111 }
1112 if (bEqual == true)
1113 return v;
1114 }
1115 }
1116 return null;
1117 }
1118
[1050]1119 /// <summary>
1120 /// Removes view and Handles Disconnection from Database if no views are left.
1121 /// </summary>
1122 /// <param name="sender"></param>
1123 /// <param name="e"></param>
[614]1124 private void ViewClosed(object sender, EventArgs e)
1125 {
1126 //Remove the sender from our document list
1127 Views.Remove(sender);
1128
1129 //If no documents left, then close RPMS connection & exit the application
1130 if ((Views.Count == 0)&&(this.AvailabilityViews.Count == 0)&&(m_bExitOK == true))
1131 {
[1474]1132 RemoteSession.EventServices.IsEventPollingEnabled = false;
1133 RemoteSession.EventServices.Unsubscribe("BSDX SCHEDULE");
1134 RemoteSession.Close();
[614]1135 Application.Exit();
1136 }
1137 }
1138
1139 private void AVViewClosed(object sender, EventArgs e)
1140 {
1141 //Remove the sender from our document list
1142 this.AvailabilityViews.Remove(sender);
1143
1144 //If no documents left, then close RPMS connection & exit the application
1145 if ((Views.Count == 0)&&(this.AvailabilityViews.Count == 0)&&(m_bExitOK == true))
1146 {
[1474]1147 RemoteSession.Close();
[614]1148 Application.Exit();
1149 }
1150 }
1151
[1098]1152 /// <summary>
1153 /// Not used
1154 /// </summary>
[614]1155 private void KeepAlive()
1156 {
1157 foreach (CGView v in _views.Keys)
1158 {
1159 CGDocument d = v.Document;
1160 DateTime dNow = DateTime.Now;
1161 DateTime dLast = d.LastRefreshed;
1162 TimeSpan tsDiff = dNow - dLast;
1163 if (tsDiff.Seconds > 180)
1164 {
1165 for (int j = 0; j < d.Resources.Count; j++)
1166 {
1167 v.RaiseRPMSEvent("SCHEDULE-" + d.Resources[j].ToString(), "");
1168 }
1169
1170 break;
1171 }
1172 }
1173 }
1174
1175 /// <summary>
1176 /// Propogate availability updates to all sRresource's doc/views
1177 /// </summary>
1178 public void UpdateViews(string sResource, string sOldResource)
1179 {
1180 if (sResource == null)
1181 return;
1182 foreach (CGView v in _views.Keys)
1183 {
1184 CGDocument d = v.Document;
1185 for (int j = 0; j < d.Resources.Count; j++)
1186 {
1187 if ((sResource == "") || (sResource == ((string) d.Resources[j])) || (sOldResource == ((string) d.Resources[j])))
1188 {
1189 d.RefreshDocument();
1190 break;
1191 }
1192 }
1193 v.UpdateTree();
1194 }
1195 }
1196
1197 /// <summary>
1198 /// Propogate availability updates to all doc/views
1199 /// </summary>
1200 public void UpdateViews()
1201 {
1202 UpdateViews("","");
1203 foreach (CGView v in _views.Keys)
1204 {
1205 v.UpdateTree();
1206 }
1207 }
1208
1209 /// <summary>
1210 /// Calls each view associated with document Doc and closes it.
1211 /// </summary>
1212 public void CloseAllViews(CGDocument doc)
1213 {
1214 //iterate through all views and call update.
1215 Hashtable h = CGDocumentManager.Current.Views;
1216
1217 CGDocument d;
1218 int nTempCount = h.Count;
1219 do
1220 {
1221 nTempCount = h.Count;
1222 foreach (CGView v in h.Keys)
1223 {
1224 d = (CGDocument) h[v];
1225 if (d == doc)
1226 {
1227 v.Close();
1228 break;
1229 }
1230 }
1231 } while ((h.Count > 0) && (nTempCount != h.Count));
1232 }
1233
1234 /// <summary>
1235 /// Calls each view associated with Availability Doc and closes it.
1236 /// </summary>
1237 public void CloseAllViews(CGAVDocument doc)
1238 {
1239 //iterate through all views and call update.
1240 Hashtable h = CGDocumentManager.Current.AvailabilityViews;
1241
1242 CGAVDocument d;
1243 int nTempCount = h.Count;
1244 do
1245 {
1246 nTempCount = h.Count;
1247 foreach (CGAVView v in h.Keys)
1248 {
1249 d = (CGAVDocument) h[v];
1250 if (d == doc)
1251 {
1252 v.Close();
1253 break;
1254 }
1255 }
1256 } while ((h.Count > 0) && (nTempCount != h.Count));
1257
1258
1259 }
1260
[1071]1261 /// <summary>
1262 /// Accomplishes Changing the Server to which you connect
1263 /// </summary>
1264 /// <remarks>
1265 /// Parameter relog-in for InitializeApp forces initialize app to use
1266 /// 1. The server the user just picked and then BMX saved off to User Preferences
1267 /// 2. A new access and verify code pair
1268 /// </remarks>
1269 /// <param name="sender">unused</param>
1270 /// <param name="e">unused</param>
[614]1271 private void mnuRPMSServer_Click(object sender, EventArgs e)
1272 {
1273 //Warn that changing servers will close all schedules
[627]1274 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]1275 return;
1276
1277 //Reconnect to RPMS and recreate all global recordsets
1278 try
1279 {
[1071]1280 // Close All, but tell the Close All method not to call Applicaiton.Exit since we still plan to continue.
1281 // Close All does not call Application.Exit, but CGView_Close handler does
[614]1282 m_bExitOK = false;
[1071]1283 CloseAll();
1284 m_bExitOK = true;
1285
1286 //Used in Do loop
[1474]1287 //bool bRetry = true;
[1071]1288
[1474]1289 /*// Do Loop to deal with changing the server and the vagaries of user choices.
[614]1290 do
1291 {
1292 try
1293 {
[1071]1294 //ChangeServerInfo does not re-login the user
1295 //It only changes the saved server information in the %APPDATA% folder
1296 //so it can be re-used when BMX tries to log in again.
1297 //Access and Verify code are prompted for in InitializeApp
[1474]1298 LoginProcess login = this.WinFramework.CreateLoginProcess();
1299 login.AttemptUserInputLogin("ReLog-in", 3, true, null);
[614]1300 bRetry = false;
1301 }
1302 catch (Exception ex)
1303 {
1304 if (ex.Message == "User cancelled.")
1305 {
1306 bRetry = false;
[1071]1307 Application.Exit();
[614]1308 return;
1309 }
[627]1310 if (MessageBox.Show("Unable to connect to VistA. " + ex.Message , "Clinical Scheduling", MessageBoxButtons.RetryCancel) == DialogResult.Retry)
[614]1311 {
1312 bRetry = true;
1313 }
1314 else
1315 {
1316 bRetry = false;
[1071]1317 Application.Exit();
[614]1318 return;
1319 }
1320 }
1321 } while (bRetry == true);
[1474]1322 */
1323
[1071]1324 //Parameter for initialize app tells it that this is a re-login and forces a new access and verify code.
1325 bool isEverythingOkay = this.InitializeApp(true);
[614]1326
[1071]1327 //if an error occurred, break out. This time we need to call Application.Exit since it's already running.
1328 if (!isEverythingOkay)
1329 {
1330 Application.Exit();
1331 return;
1332 }
[614]1333
[1071]1334 //Otherwise, everything is okay. So open document and view, then show and activate view.
1335 CGDocument doc = new CGDocument();
1336 doc.DocManager = _current;
[614]1337
[1071]1338 CGView view = new CGView();
[1073]1339 view.InitializeDocView(doc, _current, doc.StartDate, _current.WindowText);
[1071]1340
1341 view.Show();
1342 view.Activate();
1343
1344 //Application.Run need not be called b/c it is already running.
[614]1345 }
1346 catch (Exception ex)
1347 {
1348 throw ex;
1349 }
1350
1351 }
1352
[1071]1353 /// <summary>
1354 /// Accomplishes Re-login into RPMS/VISTA. Now all logic is in this event handler.
1355 /// </summary>
1356 /// <param name="sender">not used</param>
1357 /// <param name="e">not used</param>
[614]1358 private void mnuRPMSLogin_Click(object sender, EventArgs e)
1359 {
[1474]1360 mnuRPMSServer_Click(sender, e);
1361
1362 /* v 1.7 to support BMX 4 -- commented out -- smh
1363 //Warn that changing login will close all schedules
[627]1364 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]1365 return;
1366
1367 //Reconnect to RPMS and recreate all global recordsets
1368 try
1369 {
[1071]1370 // Close All, but tell the Close All method not to call Applicaiton.Exit since we still plan to continue.
1371 // Close All does not call Application.Exit, but CGView_Close handler does
[614]1372 m_bExitOK = false;
1373 CloseAll();
1374 m_bExitOK = true;
[1071]1375
[1474]1376 LoginProcess login = this.WinFramework.CreateLoginProcess();
1377 login.AttemptUserInputLogin("Clincal Scheduling", 3, true, null);
1378 //m_ConnectInfo.bmxNetLib.StartLog(); //This line turns on logging of messages
1379
1380 if (!login.WasSuccessful)
1381 {
1382 return;
1383 }
1384
1385 LocalSession local = this.WinFramework.LocalSession;
1386
1387 if ((this.WinFramework.Context.User.Division == null) && !this.WinFramework.AttemptUserInputSetDivision("Set Initial Division", null))
1388 {
1389 return;
1390 }
1391
1392 this.RemoteSession = this.WinFramework.PrimaryRemoteSession;
1393
[1071]1394 //Parameter for initialize app tells it that this is a re-login and forces a new access and verify code.
1395 bool isEverythingOkay = this.InitializeApp(true);
1396
1397 //if an error occurred, break out. This time we need to call Application.Exit since it's already running.
1398 if (!isEverythingOkay)
1399 {
1400 Application.Exit();
1401 return;
1402 }
1403
1404 //Otherwise, everything is okay. So open document and view, then show and activate view.
1405 CGDocument doc = new CGDocument();
1406 doc.DocManager = _current;
1407
1408 CGView view = new CGView();
[1073]1409 view.InitializeDocView(doc, _current, doc.StartDate, _current.WindowText);
[1071]1410
1411 view.Show();
1412 view.Activate();
1413
1414 //Application.Run need not be called b/c it is already running.
[614]1415 }
1416 catch (Exception ex)
1417 {
1418 throw ex;
1419 }
[1474]1420 */
[614]1421 }
1422
1423 delegate void CloseAllDelegate(string sMsg);
1424
1425 private void CloseAll(string sMsg)
1426 {
1427 if (sMsg == "")
1428 {
1429 sMsg = "Scheduling System Shutting Down Immediately for Maintenance.";
1430 }
1431
[620]1432 MessageBox.Show(sMsg, "Clinical Scheduling Administrator -- System Shutdown Notification", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
[614]1433
1434 CloseAll();
1435 }
1436
1437 private void CloseAll()
1438 {
1439 //Close all documents, views and connections
1440 Hashtable h = CGDocumentManager.Current.Views;
1441 int nTempCount = h.Count;
1442 do
1443 {
1444 nTempCount = h.Count;
1445 foreach (CGView v in h.Keys)
1446 {
1447 v.Close();
1448 break;
1449 }
1450 } while ((h.Count > 0) && (nTempCount != h.Count));
1451
1452 h = CGDocumentManager.Current.AvailabilityViews;
1453 nTempCount = h.Count;
1454 do
1455 {
1456 nTempCount = h.Count;
1457 foreach (CGAVView v in h.Keys)
1458 {
1459 v.Close();
1460 break;
1461 }
1462 } while ((h.Count > 0) && (nTempCount != h.Count));
1463
1464 }
1465
[1011]1466 public delegate DataTable RPMSDataTableDelegate(string CommandString, string TableName);
[614]1467
1468 public DataTable RPMSDataTable(string sSQL, string sTableName)
1469 {
1470 //Retrieves a recordset from RPMS
1471 string sErrorMessage = "";
[843]1472 DataTable dtOut;
1473
[614]1474 try
1475 {
[1011]1476 //System.IntPtr pHandle = this.Handle;
[1474]1477 RPMSDataTableDelegate rdtd = new RPMSDataTableDelegate(RemoteSession.TableFromCommand);
[1050]1478 //dtOut = (DataTable) this.Invoke(rdtd, new object[] {sSQL, sTableName});
[1474]1479 dtOut = RemoteSession.TableFromCommand(sSQL);
1480 dtOut.TableName = sTableName;
1481
[614]1482 }
[843]1483
[614]1484 catch (Exception ex)
1485 {
1486 sErrorMessage = "CGDocumentManager.RPMSDataTable error: " + ex.Message;
1487 throw ex;
1488 }
[843]1489
1490 return dtOut;
1491
[614]1492 }
1493
1494 public void ChangeDivision(System.Windows.Forms.Form frmCaller)
1495 {
[1474]1496 WinFramework.AttemptUserInputSetDivision("Change Division", frmCaller);
1497
1498 RemoteSession = WinFramework.PrimaryRemoteSession;
1499
[614]1500 foreach (CGView v in _views.Keys)
1501 {
1502 v.InitializeDocView(v.Document.DocName);
1503 v.Document.RefreshDocument();
1504 }
1505 }
1506
1507 public void ViewRefresh()
1508 {
1509 foreach (CGView v in _views.Keys)
1510 {
1511 try
1512 {
1513 v.Document.RefreshDocument();
1514 }
1515 catch (Exception ex)
1516 {
1517 Debug.Write("CGDocumentManager.ViewRefresh Exception: " + ex.Message + "\n");
1518 }
1519 finally
1520 {
1521 }
1522 }
1523 Debug.Write("DocManager refreshed all views.\n");
1524 }
1525
1526 #endregion Methods & Events
1527
1528 }
1529}
Note: See TracBrowser for help on using the repository browser.