source: Scheduling/branches/Radiology-Support/cs/bsdx0200GUISourceCode/CGDocumentManager.cs@ 1166

Last change on this file since 1166 was 1131, checked in by Sam Habiel, 14 years ago

CGDocumentManager: Localization now works from CurrentCulture, not just CurrentUICulture.
CGView: Nothing important. Designer moves around stuff; again.
Printing: Routing slip arabized; page starts at a lower level to allow for a watermark. Graphics.Dispose now called at the end of all prints to allow for faster gc.
strings: Updated with more translations.

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