/// <summary>Won't work with InvalidType.Date, InvalidType.Task, or InvalidType.TaskPopup yet.</summary> public static void SetInvalid(params InvalidType[] itypes) { if (RemotingClient.RemotingRole == RemotingRole.ClientWeb) { Meth.GetVoid(MethodBase.GetCurrentMethod(), itypes); return; } string itypeString = ""; for (int i = 0; i < itypes.Length; i++) { if (i > 0) { itypeString += ","; } itypeString += ((int)itypes[i]).ToString(); } Signalod sig = new Signalod(); sig.ITypes = itypeString; sig.DateViewing = DateTime.MinValue; sig.SigType = SignalType.Invalid; sig.TaskNum = 0; Insert(sig); }
/// <summary>Inserts a signal for each operatory in the schedule that has been changed, and for the provider the schedule is for. /// Generally should not be called outside of Schedules.cs</summary> public static void SetInvalidSched(Schedule sched) { //No need to check RemotingRole; no call to db. foreach (long opNum in sched.Ops) { Signalod sig = new Signalod() { IType = InvalidType.Schedules, DateViewing = sched.SchedDate, FKey = opNum, FKeyType = KeyType.Operatory }; Insert(sig); } //Set the signalod for the provider if (sched.ProvNum != 0) { Signalod provSig = new Signalod() { IType = InvalidType.Schedules, DateViewing = sched.SchedDate, FKey = sched.ProvNum, FKeyType = KeyType.Provider }; Insert(provSig); } }
///<summary>IComparable.CompareTo implementation. This is used to order signals. This is needed because ordering signals is too complex to do with a query.</summary> public int CompareTo(object obj) { if (!(obj is Signalod)) { throw new ArgumentException("object is not a Signalod"); } Signalod sig = (Signalod)obj; DateTime date1; DateTime date2; if (AckTime.Year < 1880) //if not acknowledged { date1 = SigDateTime; } else { date1 = AckTime; } if (sig.AckTime.Year < 1880) //if not acknowledged { date2 = sig.SigDateTime; } else { date2 = sig.AckTime; } return(date1.CompareTo(date2)); }
///<summary></summary> public static long Insert(Signalod sig) { if (RemotingClient.RemotingRole == RemotingRole.ClientWeb) { sig.SignalNum = Meth.GetLong(MethodBase.GetCurrentMethod(), sig); return(sig.SignalNum); } if (RemotingClient.RemotingRole == RemotingRole.ServerWeb) { //Refresh the cache now so that we don't have to refresh the cache when the clients update their cache. if (sig.IType == InvalidType.Fees && sig.FKeyType == KeyType.FeeSched && sig.FKey > 0) { //We don't want to refresh the entire feecache if we don't have to. Fees.InvalidateFeeSchedule(sig.FKey); } else { Cache.Refresh(sig.IType); } } //We need to explicitly get the server time in advance rather than using NOW(), because we need to update the signal object soon after creation. sig.SigDateTime = MiscData.GetNowDateTime(); sig.RemoteRole = RemotingClient.RemotingRole; return(Crud.SignalodCrud.Insert(sig)); }
///<summary></summary> public Signalod Copy() { Signalod s = (Signalod)this.MemberwiseClone(); s.ElementList = new SigElement[ElementList.Length]; ElementList.CopyTo(s.ElementList, 0); return(s); }
///<summary></summary> public static void Update(Signalod sig) { if (RemotingClient.RemotingRole == RemotingRole.ClientWeb) { Meth.GetVoid(MethodBase.GetCurrentMethod(), sig); return; } Crud.SignalodCrud.Update(sig); }
///<summary>Simplest way to use the new fKey and FKeyType. Set isBroadcast=true to process signals immediately on workstation.</summary> public static void SetInvalid(InvalidType iType, KeyType fKeyType, long fKey) { //Remoting role check performed in the Insert. Signalod sig = new Signalod(); sig.IType = iType; sig.DateViewing = DateTime.MinValue; sig.FKey = fKey; sig.FKeyType = fKeyType; Insert(sig); }
/// <summary>Schedules, when we don't have a specific FKey and want to set an invalid for the entire type. /// Includes the dateViewing parameter for Refresh.</summary> public static void SetInvalidSched(DateTime dateViewing) { //No need to check RemotingRole; no call to db. Signalod sig = new Signalod() { IType = InvalidType.Schedules, DateViewing = dateViewing }; Insert(sig); }
///<summary>Inserts an InvalidType.SmsTextMsgReceivedUnreadCount signal which tells all client machines to update the received unread SMS message count. ///To get the current count from the database, use SmsFromMobiles.GetSmsNotification().</summary> public static long InsertSmsNotification(string json) { Signalod sig = new Signalod() { IType = InvalidType.SmsTextMsgReceivedUnreadCount, FKeyType = KeyType.SmsMsgUnreadCount, MsgValue = json, }; return(Signalods.Insert(sig)); }
///<summary></summary> public static long Insert(Signalod sig) { if (RemotingClient.RemotingRole == RemotingRole.ClientWeb) { sig.SignalNum = Meth.GetLong(MethodBase.GetCurrentMethod(), sig); return(sig.SignalNum); } //we need to explicitly get the server time in advance rather than using NOW(), //because we need to update the signal object soon after creation. sig.SigDateTime = MiscData.GetNowDateTime(); return(Crud.SignalodCrud.Insert(sig)); }
///<summary>Sets the specified buttonIndex to a color and attaches the signal responsible. This is also used for the manual ack to increase responsiveness. buttonIndex is 0-based.</summary> public void SetButtonActive(int buttonIndex,Color color,Signalod activeSignal) { if(buttonIndex>=sigButStates.Length){ return;//no button to light up. } sigButStates[buttonIndex].CurrentColor=color; if(activeSignal==null){ sigButStates[buttonIndex].ActiveSignal=null; } else{ sigButStates[buttonIndex].ActiveSignal=activeSignal.Copy(); } Invalidate(); }
///<summary>Schedules, when we don't have a specific FKey and want to set an invalid for the entire type. ///Includes the dateViewing parameter for Refresh. ///A dateViewing of 01-01-0001 will be ignored because it would otherwise cause a full refresh for all connected client workstations.</summary> public static void SetInvalidSched(DateTime dateViewing) { //No need to check RemotingRole; no call to db. if (dateViewing == DateTime.MinValue) { return; //A dateViewing of 01-01-0001 will be ignored because it would otherwise cause a full refresh for all connected client workstations. } Signalod sig = new Signalod() { IType = InvalidType.Schedules, DateViewing = dateViewing }; Insert(sig); }
/// <summary>Won't work with InvalidType.Date, InvalidType.Task, or InvalidType.TaskPopup yet.</summary> public static void SetInvalid(params InvalidType[] arrayITypes) { if (RemotingClient.RemotingRole == RemotingRole.ClientWeb) { Meth.GetVoid(MethodBase.GetCurrentMethod(), arrayITypes); return; } foreach (InvalidType iType in arrayITypes) { Signalod sig = new Signalod(); sig.IType = iType; sig.DateViewing = DateTime.MinValue; Insert(sig); } }
///<summary>Insertion logic that doesn't use the cache. Has special cases for generating random PK's and handling Oracle insertions.</summary> public static void SetInvalidNoCache(params InvalidType[] itypes) { if (RemotingClient.RemotingRole == RemotingRole.ClientWeb) { Meth.GetVoid(MethodBase.GetCurrentMethod(), itypes); return; } foreach (InvalidType iType in itypes) { Signalod sig = new Signalod(); sig.IType = iType; sig.DateViewing = DateTime.MinValue; sig.RemoteRole = RemotingClient.RemotingRole; Crud.SignalodCrud.InsertNoCache(sig); } }
///<summary>Sets PK as well as DateT.</summary> public static long Insert(WebChatMessage webChatMessage) { if (RemotingClient.RemotingRole == RemotingRole.ClientWeb) { webChatMessage.WebChatMessageNum = Meth.GetLong(MethodBase.GetCurrentMethod(), webChatMessage); return(webChatMessage.WebChatMessageNum); } WebChatMisc.DbAction(delegate() { Crud.WebChatMessageCrud.Insert(webChatMessage); }); WebChatMisc.DbAction(delegate() { Signalod signalSession = new Signalod(); signalSession.IType = InvalidType.WebChatSessions; signalSession.FKey = webChatMessage.WebChatSessionNum; Signalods.Insert(signalSession); }, false); return(webChatMessage.WebChatMessageNum); }
///<summary>Inserts a signal for each operatory in the schedule that has been changed, and for the provider the schedule is for. This only ///inserts a signal for today's schedules. Generally should not be called outside of Schedules.cs</summary> public static void SetInvalidSched(params Schedule[] arraySchedules) { //No need to check RemotingRole; no call to db. //Per Nathan, we are only going to insert signals for today's schedules. Most workstations will not be looking at other days for extended //lengths of time. //Make an array of signals for every operatory involved. DateTime serverTime = MiscData.GetNowDateTime(); Signalod[] arrayOpSignals = arraySchedules .Where(x => x.SchedDate.Date == DateTime.Today || x.SchedDate.Date == serverTime.Date) .SelectMany(x => x.Ops.Select(y => new Signalod() { IType = InvalidType.Schedules, DateViewing = x.SchedDate, FKey = y, FKeyType = KeyType.Operatory, })) .ToArray(); //Make a array of signals for every provider involved. Schedule[] arrayProviderSchedules = arraySchedules.Where(x => x.ProvNum > 0).ToArray(); Signalod[] arrayProviderSignals = arrayProviderSchedules .Where(x => x.SchedDate.Date == DateTime.Today || x.SchedDate.Date == serverTime.Date) .Select(x => new Signalod() { IType = InvalidType.Schedules, DateViewing = x.SchedDate, FKey = x.ProvNum, FKeyType = KeyType.Provider, }) .ToArray(); Signalod[] arrayUniqueSignals = arrayOpSignals.Union(arrayProviderSignals).ToArray(); if (arrayUniqueSignals.Length > 1000) { //We've had offices insert tens of thousands of signals at once which severely slowed down their database. Signalod signal = new Signalod { IType = InvalidType.Schedules, DateViewing = DateTime.MinValue, //This will cause every workstation to refresh regardless of what they're viewing. }; Insert(signal); return; } Insert(arrayUniqueSignals); }
///<summary>Necessary for Union() to work when eliminating duplicates.</summary> public override bool Equals(object obj) { if (!(obj is Signalod)) { return(false); } Signalod signalOther = (Signalod)obj; if (SignalNum != signalOther.SignalNum) { return(false); } if (DateViewing != signalOther.DateViewing) { return(false); } if (SigDateTime != signalOther.SigDateTime) { return(false); } if (FKey != signalOther.FKey) { return(false); } if (FKeyType != signalOther.FKeyType) { return(false); } if (IType != signalOther.IType) { return(false); } if (RemoteRole != signalOther.RemoteRole) { return(false); } if (MsgValue != signalOther.MsgValue) { return(false); } return(true); }
///<summary>The given dateStart must be less than or equal to dateEnd. Both dates must be valid dates (not min date, etc).</summary> public static void SetInvalidSchedForOps(Dictionary <DateTime, List <long> > dictOpNumsForDates) { //No need to check RemotingRole; no call to db. List <Signalod> listOpSignals = new List <Signalod>(); foreach (DateTime date in dictOpNumsForDates.Keys) { long[] arrayUniqueOpNums = dictOpNumsForDates[date].Distinct().ToArray(); foreach (long opNum in arrayUniqueOpNums) { Signalod signalForOp = new Signalod(); signalForOp.IType = InvalidType.Schedules; signalForOp.DateViewing = date; signalForOp.FKey = opNum; signalForOp.FKeyType = KeyType.Operatory; listOpSignals.Add(signalForOp); } } Insert(listOpSignals.ToArray()); }
///<summary>Upserts the InvalidType.SmsTextMsgReceivedUnreadCount signal which tells all client machines to update the received unread SMS ///message count. There should only be max one of this signal IType in the database.</summary> public static List <SmsFromMobiles.SmsNotification> UpsertSmsNotification() { if (RemotingClient.RemotingRole == RemotingRole.ClientWeb) { return(Meth.GetObject <List <SmsFromMobiles.SmsNotification> >(MethodBase.GetCurrentMethod())); } string command = "SELECT ClinicNum,COUNT(*) AS CountUnread FROM smsfrommobile WHERE SmsStatus=0 AND IsHidden=0 GROUP BY ClinicNum " + "ORDER BY ClinicNum"; List <SmsFromMobiles.SmsNotification> ret = Db.GetTable(command).AsEnumerable() .Select(x => new SmsFromMobiles.SmsNotification() { ClinicNum = PIn.Long(x["ClinicNum"].ToString()), Count = PIn.Int(x["CountUnread"].ToString()), }).ToList(); //Insert as structured data signal so all workstations won't have to query the db to get the counts. They will get it directly from Signalod.MsgValue. string json = SmsFromMobiles.SmsNotification.GetJsonFromList(ret); //FKeyType SmsMsgUnreadCount is written to db as a string. command = "SELECT * FROM signalod WHERE IType=" + POut.Int((int)InvalidType.SmsTextMsgReceivedUnreadCount) + " AND FKeyType='" + POut.String(KeyType.SmsMsgUnreadCount.ToString()) + "' ORDER BY SigDateTime DESC LIMIT 1"; DataTable table = Db.GetTable(command); Signalod sig = Crud.SignalodCrud.TableToList(table).FirstOrDefault(); if (sig != null && sig.MsgValue == json) //No changes, not need to insert a new signal. { return(ret); //Return the list of notifications, but do not update the existing signal. } Signalods.Insert(new Signalod() { IType = InvalidType.SmsTextMsgReceivedUnreadCount, FKeyType = KeyType.SmsMsgUnreadCount, MsgValue = json, RemoteRole = RemotingClient.RemotingRole }); return(ret); }
private void listMessages_Click(object sender,EventArgs e) { if(listMessages.SelectedIndex==-1){ return; } Signalod sig=new Signalod(); sig.SigType=SignalType.Button; sig.SigText=textMessage.Text; if(listTo.SelectedIndex!=-1) { sig.ToUser=sigElementDefUser[listTo.SelectedIndex].SigText; } if(listFrom.SelectedIndex!=-1) { sig.FromUser=sigElementDefUser[listFrom.SelectedIndex].SigText; } //need to do this all as a transaction, so need to do a writelock on the signal table first. //alternatively, we could just make sure not to retrieve any signals that were less the 300ms old. Signalods.Insert(sig); SigElement element; if(listTo.SelectedIndex!=-1) { element=new SigElement(); element.SigElementDefNum=sigElementDefUser[listTo.SelectedIndex].SigElementDefNum; element.SignalNum=sig.SignalNum; SigElements.Insert(element); } //We do not insert an element for From if(listExtras.SelectedIndex!=-1) { element=new SigElement(); element.SigElementDefNum=sigElementDefExtras[listExtras.SelectedIndex].SigElementDefNum; element.SignalNum=sig.SignalNum; SigElements.Insert(element); } element=new SigElement(); element.SigElementDefNum=sigElementDefMessages[listMessages.SelectedIndex].SigElementDefNum; element.SignalNum=sig.SignalNum; SigElements.Insert(element); //reset the controls textMessage.Text=""; listFrom.SelectedIndex=-1; listTo.SelectedIndex=-1; listExtras.SelectedIndex=-1; listMessages.SelectedIndex=-1; labelSending.Visible=true; timerSending.Enabled=true; }
private void butSend_Click(object sender, System.EventArgs e){ //if(listTo.SelectedIndex==-1){ // MsgBox.Show(this,"Please select who to send the message to."); // return; //} if(textMessage.Text=="") { MsgBox.Show(this,"Please type in a message first."); return; } Signalod sig=new Signalod(); sig.SigType=SignalType.Button; sig.SigText=textMessage.Text; if(listTo.SelectedIndex!=-1) { sig.ToUser=sigElementDefUser[listTo.SelectedIndex].SigText; } if(listFrom.SelectedIndex!=-1){ sig.FromUser=sigElementDefUser[listFrom.SelectedIndex].SigText; } Signalods.Insert(sig); SigElement element; if(listTo.SelectedIndex!=-1) { element=new SigElement(); element.SigElementDefNum=sigElementDefUser[listTo.SelectedIndex].SigElementDefNum; element.SignalNum=sig.SignalNum; SigElements.Insert(element); } textMessage.Text=""; listFrom.SelectedIndex=-1; listTo.SelectedIndex=-1; listExtras.SelectedIndex=-1; listMessages.SelectedIndex=-1; labelSending.Visible=true; timerSending.Enabled=true; }
/// <summary>destinationPath includes filename (Setup.exe). destinationPath2 will create a second copy at the specified path/filename, or it will be skipped if null or empty.</summary> public static void DownloadInstallPatchFromURI(string downloadUri,string destinationPath,bool runSetupAfterDownload,bool showShutdownWindow,string destinationPath2) { string[] dblist=PrefC.GetString(PrefName.UpdateMultipleDatabases).Split(new string[] {","},StringSplitOptions.RemoveEmptyEntries); if(showShutdownWindow) { //Even if updating multiple databases, extra shutdown signals are not needed. FormShutdown FormSD=new FormShutdown(); FormSD.IsUpdate=true; FormSD.ShowDialog(); if(FormSD.DialogResult==DialogResult.OK) { //turn off signal reception for 5 seconds so this workstation will not shut down. FormOpenDental.signalLastRefreshed=MiscData.GetNowDateTime().AddSeconds(5); Signalod sig=new Signalod(); sig.ITypes=((int)InvalidType.ShutDownNow).ToString(); sig.SigType=SignalType.Invalid; Signalods.Insert(sig); Computers.ClearAllHeartBeats(Environment.MachineName);//always assume success //SecurityLogs.MakeLogEntry(Permissions.Setup,0,"Shutdown all workstations.");//can't do this because sometimes no user. } //continue on even if user clicked cancel //no other workstation will be able to start up until this value is reset. Prefs.UpdateString(PrefName.UpdateInProgressOnComputerName,Environment.MachineName); } MiscData.LockWorkstationsForDbs(dblist);//lock workstations for other db's. File.Delete(destinationPath); WebRequest wr=WebRequest.Create(downloadUri); WebResponse webResp=null; try{ webResp=wr.GetResponse(); } catch(Exception ex){ CodeBase.MsgBoxCopyPaste msgbox=new MsgBoxCopyPaste(ex.Message+"\r\nUri: "+downloadUri); msgbox.ShowDialog(); MiscData.UnlockWorkstationsForDbs(dblist);//unlock workstations since nothing was actually done. return; } int fileSize=(int)webResp.ContentLength/1024; FormProgress FormP=new FormProgress(); //start the thread that will perform the download System.Threading.ThreadStart downloadDelegate= delegate { DownloadInstallPatchWorker(downloadUri,destinationPath,ref FormP); }; Thread workerThread=new System.Threading.Thread(downloadDelegate); workerThread.Start(); //display the progress dialog to the user: FormP.MaxVal=(double)fileSize/1024; FormP.NumberMultiplication=100; FormP.DisplayText="?currentVal MB of ?maxVal MB copied"; FormP.NumberFormat="F"; FormP.ShowDialog(); if(FormP.DialogResult==DialogResult.Cancel) { workerThread.Abort(); MiscData.UnlockWorkstationsForDbs(dblist);//unlock workstations since nothing was actually done. return; } //copy to second destination directory if(destinationPath2!=null && destinationPath2!=""){ if(File.Exists(destinationPath2)){ File.Delete(destinationPath2); } File.Copy(destinationPath,destinationPath2); } //copy the Setup.exe to the AtoZ folders for the other db's. List<string> atozNameList=MiscData.GetAtoZforDb(dblist); for(int i=0;i<atozNameList.Count;i++) { if(destinationPath==Path.Combine(atozNameList[i],"Setup.exe")) {//if they are sharing an AtoZ folder. continue; } if(Directory.Exists(atozNameList[i])) { File.Copy(destinationPath,//copy the Setup.exe that was just downloaded to this AtoZ folder Path.Combine(atozNameList[i],"Setup.exe"),//to the other atozFolder true);//overwrite } } if(!runSetupAfterDownload) { return; } string msg=Lan.g("FormUpdate","Download succeeded. Setup program will now begin. When done, restart the program on this computer, then on the other computers."); if(dblist.Length > 0){ msg="Download succeeded. Setup file probably copied to other AtoZ folders as well. Setup program will now begin. When done, restart the program for each database on this computer, then on the other computers."; } if(MessageBox.Show(msg,"",MessageBoxButtons.OKCancel) !=DialogResult.OK){ //Clicking cancel gives the user a chance to avoid running the setup program, Prefs.UpdateString(PrefName.UpdateInProgressOnComputerName,"");//unlock workstations, since nothing was actually done. return; } try{ Process.Start(destinationPath); Application.Exit(); } catch{ Prefs.UpdateString(PrefName.UpdateInProgressOnComputerName,"");//unlock workstations, since nothing was actually done. MsgBox.Show(FormP,"Could not launch setup"); } }
/// <summary>Won't work with InvalidType.Date, InvalidType.Task, or InvalidType.TaskPopup yet.</summary> public static void SetInvalid(params InvalidType[] itypes) { if(RemotingClient.RemotingRole==RemotingRole.ClientWeb) { Meth.GetVoid(MethodBase.GetCurrentMethod(),itypes); return; } string itypeString=""; for(int i=0;i<itypes.Length;i++) { if(i>0) { itypeString+=","; } itypeString+=((int)itypes[i]).ToString(); } Signalod sig=new Signalod(); sig.ITypes=itypeString; sig.DateViewing=DateTime.MinValue; sig.SigType=SignalType.Invalid; sig.TaskNum=0; Insert(sig); }
///<summary></summary> public static long Insert(Signalod sig) { if(RemotingClient.RemotingRole==RemotingRole.ClientWeb) { sig.SignalNum=Meth.GetLong(MethodBase.GetCurrentMethod(),sig); return sig.SignalNum; } //we need to explicitly get the server time in advance rather than using NOW(), //because we need to update the signal object soon after creation. sig.SigDateTime=MiscData.GetNowDateTime(); return Crud.SignalodCrud.Insert(sig); }
///<summary></summary> public static void Update(Signalod sig) { if(RemotingClient.RemotingRole==RemotingRole.ClientWeb) { Meth.GetVoid(MethodBase.GetCurrentMethod(),sig); return; } Crud.SignalodCrud.Update(sig); }
/// <summary></summary> /// <param name="myButton"></param> public ODLightSignalGridClickEventArgs(int myButton,SigButDef myDef,Signalod mySignal) { buttonIndex=myButton; buttonDef=myDef; activeSignal=mySignal; }
private void timerReplicationMonitor_Tick(object sender,EventArgs e) { //this timer doesn't get turned on until after user successfully logs in. if(ReplicationServers.Listt.Count==0) {//Listt will be automatically refreshed if null. return;//user must not be using any replication } bool isSlaveMonitor=false; for(int i=0;i<ReplicationServers.Listt.Count;i++) { if(ReplicationServers.Listt[i].SlaveMonitor.ToString()!=Dns.GetHostName()) { isSlaveMonitor=true; } } if(!isSlaveMonitor) { return; } DataTable table=ReplicationServers.GetSlaveStatus(); if(table.Rows.Count==0) { return; } if(table.Rows[0]["Replicate_Do_Db"].ToString()!=DataConnection.GetDatabaseName()) {//if the database we're connected to is not even involved in replication return; } string status=table.Rows[0]["Slave_SQL_Running"].ToString(); if(status=="Yes") { return; } //Shut down all copies of OD and set ReplicationFailureAtServer_id to this server_id //No workstations will be able to connect to this single server while this flag is set. Prefs.UpdateInt(PrefName.ReplicationFailureAtServer_id,ReplicationServers.Server_id); //shut down all workstations on all servers FormOpenDental.signalLastRefreshed=MiscData.GetNowDateTime().AddSeconds(5); Signalod sig=new Signalod(); sig.ITypes=((int)InvalidType.ShutDownNow).ToString(); sig.SigType=SignalType.Invalid; Signalods.Insert(sig); Computers.ClearAllHeartBeats(Environment.MachineName);//always assume success timerReplicationMonitor.Enabled=false; MsgBox.Show(this,"This database is temporarily unavailable. Please connect instead to your alternate database at the other location."); Application.Exit(); }
private void lightSignalGrid1_ButtonClick(object sender,OpenDental.UI.ODLightSignalGridClickEventArgs e) { if(e.ActiveSignal!=null){//user trying to ack an existing light signal Signalods.AckButton(e.ButtonIndex+1,signalLastRefreshed); //then, manually ack the light on this computer. The second ack in a few seconds will be ignored. lightSignalGrid1.SetButtonActive(e.ButtonIndex,Color.White,null); SigButDef butDef=SigButDefs.GetByIndex(e.ButtonIndex,SigButDefList); if(butDef!=null) { PaintOnIcon(butDef.SynchIcon,Color.White); } return; } if(e.ButtonDef==null || e.ButtonDef.ElementList.Length==0){//there is no signal to send return; } //user trying to send a signal Signalod sig=new Signalod(); sig.SigType=SignalType.Button; //sig.ToUser=sigElementDefUser[listTo.SelectedIndex].SigText; //sig.FromUser=sigElementDefUser[listFrom.SelectedIndex].SigText; //need to do this all as a transaction? Signalods.Insert(sig); int row=0; Color color=Color.White; SigElementDef def; SigElement element; SigButDefElement[] butElements=SigButDefElements.GetForButton(e.ButtonDef.SigButDefNum); for(int i=0;i<butElements.Length;i++){ element=new SigElement(); element.SigElementDefNum=butElements[i].SigElementDefNum; element.SignalNum=sig.SignalNum; SigElements.Insert(element); if(SigElementDefs.GetElement(element.SigElementDefNum).SigElementType==SignalElementType.User){ sig.ToUser=SigElementDefs.GetElement(element.SigElementDefNum).SigText; Signalods.Update(sig); } def=SigElementDefs.GetElement(element.SigElementDefNum); if(def.LightRow!=0) { row=def.LightRow; } if(def.LightColor.ToArgb()!=Color.White.ToArgb()) { color=def.LightColor; } } sig.ElementList=new SigElement[0];//we don't really care about these if(row!=0 && color!=Color.White) { lightSignalGrid1.SetButtonActive(row-1,color,sig);//this just makes it seem more responsive. //we can skip painting on the icon } }
private void timerReplicationMonitor_Tick(object sender,EventArgs e) { //this timer doesn't get turned on until after user successfully logs in. if(ReplicationServers.Listt.Count==0) {//Listt will be automatically refreshed if null. return;//user must not be using any replication } bool isSlaveMonitor=false; for(int i=0;i<ReplicationServers.Listt.Count;i++) { if(ReplicationServers.Listt[i].SlaveMonitor.ToString()!=Dns.GetHostName()) { isSlaveMonitor=true; } } if(!isSlaveMonitor) { return; } DataTable table=ReplicationServers.GetSlaveStatus(); if(table.Rows.Count==0) { return; } if(table.Rows[0]["Replicate_Do_Db"].ToString().ToLower()!=DataConnection.GetDatabaseName().ToLower()) {//if the database we're connected to is not even involved in replication return; } string status=table.Rows[0]["Slave_SQL_Running"].ToString(); if(status=="Yes") { _isReplicationSlaveStopped=false; return; } if(table.Rows[0]["Last_Errno"].ToString()=="0" && table.Rows[0]["Last_Error"].ToString()=="") { //The slave SQL is not running, but there was not an error. //This happens when the slave is manually stopped with an SQL statement, but stopping the slave does not hurt anything, so we should not prevent the user from using OD. if(!_isReplicationSlaveStopped) { _isReplicationSlaveStopped=true; MessageBox.Show(Lan.g(this,"Warning: Replication data receive is off at server ")+ReplicationServers.GetForLocalComputer().Descript+".\r\n" +Lan.g(this,"The server will not receive updates until the slave is started again.")+"\r\n" +Lan.g(this,"Contact your IT admin to run the SQL command SLAVE START.") ); } return; } //Shut down all copies of OD and set ReplicationFailureAtServer_id to this server_id //No workstations will be able to connect to this single server while this flag is set. Prefs.UpdateInt(PrefName.ReplicationFailureAtServer_id,ReplicationServers.Server_id); //shut down all workstations on all servers FormOpenDental.signalLastRefreshed=MiscData.GetNowDateTime().AddSeconds(5); Signalod sig=new Signalod(); sig.ITypes=((int)InvalidType.ShutDownNow).ToString(); sig.SigType=SignalType.Invalid; Signalods.Insert(sig); Computers.ClearAllHeartBeats(Environment.MachineName);//always assume success timerReplicationMonitor.Enabled=false; MsgBox.Show(this,"This database is temporarily unavailable. Please connect instead to your alternate database at the other location."); Application.Exit(); }
///<summary>This is called when any local data becomes outdated. It's purpose is to tell the other computers to update certain local data.</summary> private void DataValid_BecameInvalid(OpenDental.ValidEventArgs e){ if(e.OnlyLocal){//Currently used after doing a restore from FormBackup so that the local cache is forcefully updated. if(!PrefsStartup()){//?? return; } RefreshLocalData(InvalidType.AllLocal);//does local computer only return; } if(!e.ITypes.Contains((int)InvalidType.Date) //local refresh for dates is handled within ContrAppt, not here && !e.ITypes.Contains((int)InvalidType.Task)//Tasks are not "cached" data. && !e.ITypes.Contains((int)InvalidType.TaskPopup)) { InvalidType[] itypeArray=new InvalidType[e.ITypes.Count]; for(int i=0;i<itypeArray.Length;i++){ itypeArray[i]=(InvalidType)e.ITypes[i]; } RefreshLocalData(itypeArray);//does local computer } if(e.ITypes.Contains((int)InvalidType.Task) || e.ITypes.Contains((int)InvalidType.TaskPopup)) { //One of the two task lists needs to be refreshed on this instance of OD if(userControlTasks1.Visible) { userControlTasks1.RefreshTasks(); } //See if FormTasks is currently open. if(ContrManage2!=null && ContrManage2.FormT!=null && !ContrManage2.FormT.IsDisposed) { ContrManage2.FormT.RefreshUserControlTasks(); } } string itypeString=""; for(int i=0;i<e.ITypes.Count;i++){ if(i>0){ itypeString+=","; } itypeString+=e.ITypes[i].ToString(); } Signalod sig=new Signalod(); sig.ITypes=itypeString; if(e.ITypes.Contains((int)InvalidType.Date)){ sig.DateViewing=e.DateViewing; } else{ sig.DateViewing=DateTime.MinValue; } sig.SigType=SignalType.Invalid; if(e.ITypes.Contains((int)InvalidType.Task) || e.ITypes.Contains((int)InvalidType.TaskPopup)){ sig.TaskNum=e.TaskNum; } Signalods.Insert(sig); }
private void menuItemShutdown_Click(object sender,EventArgs e) { if(!Security.IsAuthorized(Permissions.Setup)) { return; } FormShutdown FormS=new FormShutdown(); FormS.ShowDialog(); if(FormS.DialogResult!=DialogResult.OK) { return; } //turn off signal reception for 5 seconds so this workstation will not shut down. signalLastRefreshed=MiscData.GetNowDateTime().AddSeconds(5); Signalod sig=new Signalod(); sig.ITypes=((int)InvalidType.ShutDownNow).ToString(); sig.SigType=SignalType.Invalid; Signalods.Insert(sig); Computers.ClearAllHeartBeats(Environment.MachineName);//always assume success SecurityLogs.MakeLogEntry(Permissions.Setup,0,"Shutdown all workstations."); }
///<summary></summary> protected void OnButtonClicked(int myButton,SigButDef myDef,Signalod mySignal) { ODLightSignalGridClickEventArgs bArgs=new ODLightSignalGridClickEventArgs(myButton,myDef,mySignal); if(ButtonClick!=null) ButtonClick(this,bArgs); }
///<summary>This is called when any local data becomes outdated. It's purpose is to tell the other computers to update certain local data.</summary> private void DataValid_BecameInvalid(OpenDental.ValidEventArgs e) { if(e.OnlyLocal){ if(!PrefsStartup()){//?? return; } RefreshLocalData(InvalidType.AllLocal);//does local computer only return; } if(!e.ITypes.Contains((int)InvalidType.Date) && !e.ITypes.Contains((int)InvalidType.Task) && !e.ITypes.Contains((int)InvalidType.TaskPopup)){ //local refresh for dates is handled within ContrAppt, not here InvalidType[] itypeArray=new InvalidType[e.ITypes.Count]; for(int i=0;i<itypeArray.Length;i++){ itypeArray[i]=(InvalidType)e.ITypes[i]; } RefreshLocalData(itypeArray);//does local computer } string itypeString=""; for(int i=0;i<e.ITypes.Count;i++){ if(i>0){ itypeString+=","; } itypeString+=e.ITypes[i].ToString(); } Signalod sig=new Signalod(); sig.ITypes=itypeString; if(e.ITypes.Contains((int)InvalidType.Date)){ sig.DateViewing=e.DateViewing; } else{ sig.DateViewing=DateTime.MinValue; } sig.SigType=SignalType.Invalid; if(e.ITypes.Contains((int)InvalidType.Task) || e.ITypes.Contains((int)InvalidType.TaskPopup)){ sig.TaskNum=e.TaskNum; } Signalods.Insert(sig); }
/// <summary>destinationPath includes filename (Setup.exe). destinationPath2 will create a second copy at the specified path/filename, or it will be skipped if null or empty.</summary> public static void DownloadInstallPatchFromURI(string downloadUri,string destinationPath,bool runSetupAfterDownload,bool showShutdownWindow,string destinationPath2){ string[] dblist=PrefC.GetString(PrefName.UpdateMultipleDatabases).Split(new string[] {","},StringSplitOptions.RemoveEmptyEntries); if(showShutdownWindow) { //Even if updating multiple databases, extra shutdown signals are not needed. FormShutdown FormSD=new FormShutdown(); FormSD.IsUpdate=true; FormSD.ShowDialog(); if(FormSD.DialogResult==DialogResult.OK) { //turn off signal reception for 5 seconds so this workstation will not shut down. FormOpenDental.signalLastRefreshed=MiscData.GetNowDateTime().AddSeconds(5); Signalod sig=new Signalod(); sig.ITypes=((int)InvalidType.ShutDownNow).ToString(); sig.SigType=SignalType.Invalid; Signalods.Insert(sig); Computers.ClearAllHeartBeats(Environment.MachineName);//always assume success //SecurityLogs.MakeLogEntry(Permissions.Setup,0,"Shutdown all workstations.");//can't do this because sometimes no user. } //continue on even if user clicked cancel //no other workstation will be able to start up until this value is reset. Prefs.UpdateString(PrefName.UpdateInProgressOnComputerName,Environment.MachineName); } MiscData.LockWorkstationsForDbs(dblist);//lock workstations for other db's. File.Delete(destinationPath); WebRequest wr=WebRequest.Create(downloadUri); WebResponse webResp=null; try{ webResp=wr.GetResponse(); } catch(Exception ex){ CodeBase.MsgBoxCopyPaste msgbox=new MsgBoxCopyPaste(ex.Message+"\r\nUri: "+downloadUri); msgbox.ShowDialog(); MiscData.UnlockWorkstationsForDbs(dblist);//unlock workstations since nothing was actually done. return; } int fileSize=(int)webResp.ContentLength/1024; FormProgress FormP=new FormProgress(); //start the thread that will perform the download System.Threading.ThreadStart downloadDelegate= delegate { DownloadInstallPatchWorker(downloadUri,destinationPath,ref FormP); }; Thread workerThread=new System.Threading.Thread(downloadDelegate); workerThread.Start(); //display the progress dialog to the user: FormP.MaxVal=(double)fileSize/1024; FormP.NumberMultiplication=100; FormP.DisplayText="?currentVal MB of ?maxVal MB copied"; FormP.NumberFormat="F"; FormP.ShowDialog(); if(FormP.DialogResult==DialogResult.Cancel) { workerThread.Abort(); MiscData.UnlockWorkstationsForDbs(dblist);//unlock workstations since nothing was actually done. return; } //copy to second destination directory if(destinationPath2!=null && destinationPath2!=""){ if(File.Exists(destinationPath2)){ File.Delete(destinationPath2); } File.Copy(destinationPath,destinationPath2); } //copy the Setup.exe to the AtoZ folders for the other db's. List<string> atozNameList=MiscData.GetAtoZforDb(dblist); for(int i=0;i<atozNameList.Count;i++) { if(destinationPath==Path.Combine(atozNameList[i],"Setup.exe")) {//if they are sharing an AtoZ folder. continue; } if(Directory.Exists(atozNameList[i])) { File.Copy(destinationPath,//copy the Setup.exe that was just downloaded to this AtoZ folder Path.Combine(atozNameList[i],"Setup.exe"),//to the other atozFolder true);//overwrite } } if(!runSetupAfterDownload) { return; } string msg=Lan.g("FormUpdate","Download succeeded. Setup program will now begin. When done, restart the program on this computer, then on the other computers."); if(dblist.Length > 0){ msg="Download succeeded. Setup file probably copied to other AtoZ folders as well. Setup program will now begin. When done, restart the program for each database on this computer, then on the other computers."; } if(MessageBox.Show(msg,"",MessageBoxButtons.OKCancel) !=DialogResult.OK){ //Clicking cancel gives the user a chance to avoid running the setup program, Prefs.UpdateString(PrefName.UpdateInProgressOnComputerName,"");//unlock workstations, since nothing was actually done. return; } #region Stop OpenDent Services //If the update has been initiated from the designated update server then try and stop all "OpenDent..." services. //They will be automatically restarted once Open Dental has successfully upgraded. if(PrefC.GetString(PrefName.WebServiceServerName)!="" && ODEnvironment.IdIsThisComputer(PrefC.GetString(PrefName.WebServiceServerName))) { List<ServiceController> listServices=ODEnvironment.GetAllOpenDentServices(); StringBuilder strBuilder=new StringBuilder(); if(listServices.Count>0) { FormAlertSimple FormAS=new FormAlertSimple(Lan.g("FormUpdate","Stopping services...")); FormAS.Show(); Application.DoEvents();//Allows the form to show up on top of FormUpdate right away. //Loop through all Open Dental services and stop them if they have not stopped or are not pending a stop so that their binaries can be updated. for(int i=0;i<listServices.Count;i++) { if(listServices[i].Status==ServiceControllerStatus.Stopped || listServices[i].Status==ServiceControllerStatus.StopPending) { continue;//Already stopped. Calling Stop again will guarantee an exception is thrown. Do not try calling Stop on a stopped service. } try { listServices[i].Stop(); listServices[i].WaitForStatus(ServiceControllerStatus.Stopped,new TimeSpan(0,0,7)); } catch { //An InvalidOperationException will get thrown if the service could not stop. E.g. the user is not running Open Dental as an administrator. strBuilder.AppendLine(listServices[i].DisplayName); } } FormAS.Close(); //Notify the user to go manually stop the services that could not automatically stop. if(strBuilder.ToString()!="") { MsgBoxCopyPaste msgBCP=new MsgBoxCopyPaste(Lan.g("FormUpdate","The following services could not be stopped. You need to manually stop them before continuing.") +"\r\n"+strBuilder.ToString()); msgBCP.ShowDialog(); } } } #endregion try { Process.Start(destinationPath); Application.Exit(); } catch{ Prefs.UpdateString(PrefName.UpdateInProgressOnComputerName,"");//unlock workstations, since nothing was actually done. MsgBox.Show(FormP,"Could not launch setup"); } }