Example #1
0
        private void FillMain()
        {
            int      parent;
            DateTime date;

            if (TreeHistory.Count > 0)           //not on main trunk
            {
                parent = ((TaskList)TreeHistory[TreeHistory.Count - 1]).TaskListNum;
                date   = DateTime.MinValue;
            }
            else              //one of the main trunks
            {
                parent = 0;
                date   = cal.SelectionStart;
            }
            RefreshMainLists(parent, date);
            if (TreeHistory.Count == 0 &&      //main trunk
                (tabContr.SelectedIndex == 2 || tabContr.SelectedIndex == 3 || tabContr.SelectedIndex == 4))               //any of the dated groups
            {
                //clear any lists which are derived from a repeating list and which do not have any itmes checked off
                bool changeMade = false;
                for (int i = 0; i < TaskListsList.Length; i++)
                {
                    if (TaskListsList[i].FromNum == 0)                   //ignore because not derived from a repeating list
                    {
                        continue;
                    }
                    if (!AnyAreMarkedComplete(TaskListsList[i]))
                    {
                        DeleteEntireList(TaskListsList[i]);
                        changeMade = true;
                    }
                }
                //clear any tasks which are derived from a repeating tast and which are not checked off
                for (int i = 0; i < TasksList.Length; i++)
                {
                    if (TasksList[i].FromNum == 0)
                    {
                        continue;
                    }
                    if (!TasksList[i].TaskStatus)
                    {
                        Tasks.Delete(TasksList[i]);
                        changeMade = true;
                    }
                }
                if (changeMade)
                {
                    RefreshMainLists(parent, date);
                }
                //now add back any repeating lists and tasks that meet the criteria
                //Get lists of all repeating lists and tasks of one type.  We will pick items from these two lists.
                TaskList[] repeatingLists = new TaskList[0];
                Task[]     repeatingTasks = new Task[0];
                switch (tabContr.SelectedIndex)
                {
                case 2:
                    repeatingLists = TaskLists.Refresh(-1, DateTime.MinValue, TaskDateType.Day, true);
                    repeatingTasks = Tasks.Refresh(-1, DateTime.MinValue, TaskDateType.Day, true);
                    break;

                case 3:
                    repeatingLists = TaskLists.Refresh(-1, DateTime.MinValue, TaskDateType.Week, true);
                    repeatingTasks = Tasks.Refresh(-1, DateTime.MinValue, TaskDateType.Week, true);
                    break;

                case 4:
                    repeatingLists = TaskLists.Refresh(-1, DateTime.MinValue, TaskDateType.Month, true);
                    repeatingTasks = Tasks.Refresh(-1, DateTime.MinValue, TaskDateType.Month, true);
                    break;
                }
                //loop through list and add back any that meet criteria.
                changeMade = false;
                bool alreadyExists;
                for (int i = 0; i < repeatingLists.Length; i++)
                {
                    //if already exists, skip
                    alreadyExists = false;
                    for (int j = 0; j < TaskListsList.Length; j++)               //loop through Main list
                    {
                        if (TaskListsList[j].FromNum == repeatingLists[i].TaskListNum)
                        {
                            alreadyExists = true;
                            break;
                        }
                    }
                    if (alreadyExists)
                    {
                        continue;
                    }
                    //otherwise, duplicate the list
                    repeatingLists[i].DateTL      = date;
                    repeatingLists[i].FromNum     = repeatingLists[i].TaskListNum;
                    repeatingLists[i].IsRepeating = false;
                    repeatingLists[i].Parent      = 0;
                    repeatingLists[i].ObjectType  = 0;                 //user will have to set explicitly
                    DuplicateExistingList(repeatingLists[i], true);
                    changeMade = true;
                }
                for (int i = 0; i < repeatingTasks.Length; i++)
                {
                    //if already exists, skip
                    alreadyExists = false;
                    for (int j = 0; j < TasksList.Length; j++)               //loop through Main list
                    {
                        if (TasksList[j].FromNum == repeatingTasks[i].TaskNum)
                        {
                            alreadyExists = true;
                            break;
                        }
                    }
                    if (alreadyExists)
                    {
                        continue;
                    }
                    //otherwise, duplicate the task
                    repeatingTasks[i].DateTask    = date;
                    repeatingTasks[i].FromNum     = repeatingTasks[i].TaskNum;
                    repeatingTasks[i].IsRepeating = false;
                    repeatingTasks[i].TaskListNum = 0;
                    Tasks.InsertOrUpdate(repeatingTasks[i], true);
                    changeMade = true;
                }
                if (changeMade)
                {
                    RefreshMainLists(parent, date);
                }
            }            //if main trunk on dated group
            listMain.Items.Clear();
            ListViewItem item;
            string       dateStr = "";

            for (int i = 0; i < TaskListsList.Length; i++)
            {
                dateStr = "";
                if (TaskListsList[i].DateTL.Year > 1880 &&
                    tabContr.SelectedIndex == 0)                     //main
                {
                    //dateStr=TaskListsList[i].DateTL.ToShortDateString()+" - ";
                    if (TaskListsList[i].DateType == TaskDateType.Day)
                    {
                        dateStr = TaskListsList[i].DateTL.ToShortDateString() + " - ";
                    }
                    else if (TaskListsList[i].DateType == TaskDateType.Week)
                    {
                        dateStr = Lan.g(this, "Week of") + " " + TaskListsList[i].DateTL.ToShortDateString() + " - ";
                    }
                    else if (TaskListsList[i].DateType == TaskDateType.Month)
                    {
                        dateStr = TaskListsList[i].DateTL.ToString("MMMM") + " - ";
                    }
                }
                item             = new ListViewItem(dateStr + TaskListsList[i].Descript, 0);
                item.ToolTipText = item.Text;
                listMain.Items.Add(item);
            }
            string objDesc = "";

            for (int i = 0; i < TasksList.Length; i++)
            {
                //checked=1, unchecked=2
                dateStr = "";
                if (tabContr.SelectedIndex == 0)               //main
                {
                    if (TasksList[i].DateTask.Year > 1880)
                    {
                        if (TasksList[i].DateType == TaskDateType.Day)
                        {
                            dateStr = TasksList[i].DateTask.ToShortDateString() + " - ";
                        }
                        else if (TasksList[i].DateType == TaskDateType.Week)
                        {
                            dateStr = Lan.g(this, "Week of") + " " + TasksList[i].DateTask.ToShortDateString() + " - ";
                        }
                        else if (TasksList[i].DateType == TaskDateType.Month)
                        {
                            dateStr = TasksList[i].DateTask.ToString("MMMM") + " - ";
                        }
                    }
                    else if (TasksList[i].DateTimeEntry.Year > 1880)
                    {
                        dateStr = TasksList[i].DateTimeEntry.ToShortDateString() + " - ";
                    }
                }
                objDesc = "";
                if (TasksList[i].ObjectType == TaskObjectType.Patient)
                {
                    if (TasksList[i].KeyNum != 0)
                    {
                        objDesc = Patients.GetPat(TasksList[i].KeyNum).GetNameLF() + " - ";
                    }
                }
                else if (TasksList[i].ObjectType == TaskObjectType.Appointment)
                {
                    if (TasksList[i].KeyNum != 0)
                    {
                        Appointment AptCur = Appointments.GetOneApt(TasksList[i].KeyNum);
                        if (AptCur != null)
                        {
                            objDesc = Patients.GetPat(AptCur.PatNum).GetNameLF()
                                      + "  " + AptCur.AptDateTime.ToString()
                                      + "  " + AptCur.ProcDescript
                                      + "  " + AptCur.Note
                                      + " - ";
                        }
                    }
                }
                if (TasksList[i].TaskStatus)                 //complete
                {
                    item = new ListViewItem(dateStr + objDesc + TasksList[i].Descript, 1);
                }
                else
                {
                    item = new ListViewItem(dateStr + objDesc + TasksList[i].Descript, 2);
                }
                item.ToolTipText = item.Text;
                listMain.Items.Add(item);
            }
        }
Example #2
0
        private void OnPaste_Click()
        {
            if (ClipTaskList != null)           //a taskList is on the clipboard
            {
                TaskList newTL = ClipTaskList.Copy();
                if (TreeHistory.Count > 0)               //not on main trunk
                {
                    newTL.Parent = ((TaskList)TreeHistory[TreeHistory.Count - 1]).TaskListNum;
                    switch (tabContr.SelectedIndex)
                    {
                    case 0:                            //main
                        //even though usually only trunks are dated, we will leave the date alone in main
                        //category since user may wish to preserve it. All other children get date cleared.
                        break;

                    case 1:                               //repeating
                        newTL.DateTL = DateTime.MinValue; //never a date
                        //leave dateType alone, since that affects how it repeats
                        break;

                    case 2:                                 //day
                    case 3:                                 //week
                    case 4:                                 //month
                        newTL.DateTL   = DateTime.MinValue; //children do not get dated
                        newTL.DateType = TaskDateType.None; //this doesn't matter either for children
                        break;
                    }
                }
                else                  //one of the main trunks
                {
                    newTL.Parent = 0;
                    switch (tabContr.SelectedIndex)
                    {
                    case 0:                            //main
                        newTL.DateTL   = DateTime.MinValue;
                        newTL.DateType = TaskDateType.None;
                        break;

                    case 1:                               //repeating
                        newTL.DateTL = DateTime.MinValue; //never a date
                        //newTL.DateType=TaskDateType.None;//leave alone
                        break;

                    case 2:                            //day
                        newTL.DateTL   = cal.SelectionStart;
                        newTL.DateType = TaskDateType.Day;
                        break;

                    case 3:                            //week
                        newTL.DateTL   = cal.SelectionStart;
                        newTL.DateType = TaskDateType.Week;
                        break;

                    case 4:                            //month
                        newTL.DateTL   = cal.SelectionStart;
                        newTL.DateType = TaskDateType.Month;
                        break;
                    }
                }
                if (tabContr.SelectedIndex == 1)               //repeating
                {
                    newTL.IsRepeating = true;
                }
                else
                {
                    newTL.IsRepeating = false;
                }
                newTL.FromNum = 0;              //always
                if (tabContr.SelectedIndex == 0)
                {
                    DuplicateExistingList(newTL, true);
                }
                else
                {
                    DuplicateExistingList(newTL, false);
                }
            }
            if (ClipTask != null)           //a task is on the clipboard
            {
                Task newT = ClipTask.Copy();
                if (TreeHistory.Count > 0)               //not on main trunk
                {
                    newT.TaskListNum = ((TaskList)TreeHistory[TreeHistory.Count - 1]).TaskListNum;
                    switch (tabContr.SelectedIndex)
                    {
                    case 0:                            //main
                        //even though usually only trunks are dated, we will leave the date alone in main
                        //category since user may wish to preserve it. All other children get date cleared.
                        break;

                    case 1:                                //repeating
                        newT.DateTask = DateTime.MinValue; //never a date
                        //leave dateType alone, since that affects how it repeats
                        break;

                    case 2:                                //day
                    case 3:                                //week
                    case 4:                                //month
                        newT.DateTask = DateTime.MinValue; //children do not get dated
                        newT.DateType = TaskDateType.None; //this doesn't matter either for children
                        break;
                    }
                }
                else                  //one of the main trunks
                {
                    newT.TaskListNum = 0;
                    switch (tabContr.SelectedIndex)
                    {
                    case 0:                            //main
                        newT.DateTask = DateTime.MinValue;
                        newT.DateType = TaskDateType.None;
                        break;

                    case 1:                                //repeating
                        newT.DateTask = DateTime.MinValue; //never a date
                        //newTL.DateType=TaskDateType.None;//leave alone
                        break;

                    case 2:                            //day
                        newT.DateTask = cal.SelectionStart;
                        newT.DateType = TaskDateType.Day;
                        break;

                    case 3:                            //week
                        newT.DateTask = cal.SelectionStart;
                        newT.DateType = TaskDateType.Week;
                        break;

                    case 4:                            //month
                        newT.DateTask = cal.SelectionStart;
                        newT.DateType = TaskDateType.Month;
                        break;
                    }
                }
                if (tabContr.SelectedIndex == 1)               //repeating
                {
                    newT.IsRepeating = true;
                }
                else
                {
                    newT.IsRepeating = false;
                }
                newT.FromNum = 0;              //always
                Tasks.InsertOrUpdate(newT, true);
            }
            if (WasCut)
            {
                if (ClipTaskList != null)
                {
                    DeleteEntireList(ClipTaskList);
                }
                else if (ClipTask != null)
                {
                    Tasks.Delete(ClipTask);
                }
            }
            FillMain();
        }
Example #3
0
        private void butOK_Click(object sender, EventArgs e)
        {
            if (textNote.Text == "")
            {
                MsgBox.Show(this, "Please enter a note, or delete this entry.");
                return;
            }
            if (Tasks.IsTaskDeleted(TaskNoteCur.TaskNum))               //If this is for a new task we do have a valid TaskNum because of pre-insert
            {
                MsgBox.Show(this, "The task for this note was deleted.");
                return;                //Don't allow user to create orphaned notes, or try to edit a tasknote that was probably deleted too.
            }
            //We need the old datetime to check if the user made any changes.  We overrite TaskNoteCur's date time below so need to get it here.
            DateTime dateTimeNoteOld = TaskNoteCur.DateTimeNote;

            try {
                TaskNoteCur.DateTimeNote = DateTime.Parse(textDateTime.Text);
            }
            catch {
                MsgBox.Show(this, "Please fix date.");
                return;
            }
            if (TaskNoteCur.IsNew)
            {
                TaskNoteCur.Note = textNote.Text;
                TaskNotes.Insert(TaskNoteCur);
                Tasks.TaskEditCreateLog(Permissions.TaskNoteEdit, Lan.g(this, "Added task note"), Tasks.GetOne(TaskNoteCur.TaskNum));
                DialogResult = DialogResult.OK;
                OnEditComplete();
            }
            else if (TaskNoteCur.Note != textNote.Text || dateTimeNoteOld != TaskNoteCur.DateTimeNote)
            {
                TaskNoteCur.Note = textNote.Text;
                TaskNotes.Update(TaskNoteCur);
                Tasks.TaskEditCreateLog(Permissions.TaskNoteEdit, Lan.g(this, "Task note changed"), Tasks.GetOne(TaskNoteCur.TaskNum));
                DialogResult = DialogResult.OK;
                OnEditComplete();
            }
            else
            {
                //Intentionally blank, user opened an existing task note and did not change the note but clicked OK.
                //This is effectively equivilent to a Cancel click
                DialogResult = DialogResult.Cancel;
            }
            Close();            //Needed because the window is called as a non-modal window.
        }
Example #4
0
        private void butMerge_Click(object sender, EventArgs e)
        {
            if (_patTo.PatNum == _patFrom.PatNum)
            {
                MsgBox.Show(this, "Cannot merge a patient account into itself. Please select a different patient to merge from.");
                return;
            }
            string msgText = "";

            if (_patFrom.FName.Trim().ToLower() != _patTo.FName.Trim().ToLower() ||
                _patFrom.LName.Trim().ToLower() != _patTo.LName.Trim().ToLower() ||
                _patFrom.Birthdate != _patTo.Birthdate)
            {            //mismatch
                msgText = Lan.g(this, "The two patients do not have the same first name, last name, and birthdate.");
                if (Programs.UsingEcwTightOrFullMode())
                {
                    msgText += "\r\n" + Lan.g(this, "The patients must first be merged from within eCW, then immediately merged in the same order in Open Dental.  "
                                              + "If the patients are not merged in this manner, some information may not properly bridge between eCW and Open Dental.");
                }
                msgText += "\r\n\r\n"
                           + Lan.g(this, "Into patient name") + ": " + Patients.GetNameFLnoPref(_patTo.LName, _patTo.FName, "") + ", "     //using Patients.GetNameFLnoPref to omit MiddleI
                           + Lan.g(this, "Into patient birthdate") + ": " + _patTo.Birthdate.ToShortDateString() + "\r\n"
                           + Lan.g(this, "From patient name") + ": " + Patients.GetNameFLnoPref(_patFrom.LName, _patFrom.FName, "") + ", " //using Patients.GetNameFLnoPref to omit MiddleI
                           + Lan.g(this, "From patient birthdate") + ": " + _patFrom.Birthdate.ToShortDateString() + "\r\n\r\n"
                           + Lan.g(this, "Merge the patient on the bottom into the patient shown on the top?");
                if (MessageBox.Show(msgText, "", MessageBoxButtons.YesNo) != DialogResult.Yes)
                {
                    return;                    //The user chose not to merge
                }
            }
            else              //name and bd match
            {
                if (!MsgBox.Show(this, MsgBoxButtons.YesNo, "Merge the patient at the bottom into the patient shown at the top?"))
                {
                    return;                    //The user chose not to merge.
                }
            }
            if (_patFrom.PatNum == _patFrom.Guarantor)
            {
                Family fam = Patients.GetFamily(_patFrom.PatNum);
                if (fam.ListPats.Length > 1)
                {
                    msgText = Lan.g(this, "The patient you have chosen to merge from is a guarantor.  Merging this patient into another account will cause all "
                                    + "family members of the patient being merged from to be moved into the same family as the patient account being merged into.") + "\r\n"
                              + Lan.g(this, "Do you wish to continue with the merge?");
                    if (MessageBox.Show(msgText, "", MessageBoxButtons.YesNo) != DialogResult.Yes)
                    {
                        return;                        //The user chose not to merge.
                    }
                }
            }
            Cursor = Cursors.WaitCursor;
            List <Task> listPatientTasks  = Tasks.RefreshPatientTickets(_patFrom.PatNum);        //Get this before the merge, because the merge updates Task.KeyNum.
            bool        isSuccessfulMerge = false;

            try {
                isSuccessfulMerge = Patients.MergeTwoPatients(_patTo.PatNum, _patFrom.PatNum);
            }
            catch (Exception ex) {
                SecurityLogs.MakeLogEntry(Permissions.PatientMerge, _patTo.PatNum,
                                          "Error occurred while merging Patient: " + _patFrom.GetNameFL() + "\r\nPatNum From: " + _patFrom.PatNum + "\r\nPatNum To: " + _patTo.PatNum);
                Cursor = Cursors.Default;
                FriendlyException.Show(Lan.g(this, "Unable to fully merge patients.  Contact support."), ex);
            }
            if (isSuccessfulMerge)
            {
                //The patient has been successfully merged.
                #region Refresh Patient's Tasks
                List <Signalod> listSignals = new List <Signalod>();
                foreach (Task task in listPatientTasks)
                {
                    Signalod signal = new Signalod();
                    signal.IType       = InvalidType.Task;
                    signal.FKeyType    = KeyType.Task;
                    signal.FKey        = task.TaskNum;
                    signal.DateViewing = DateTime.MinValue;                  //Mimics Signalods.SetInvalid()
                    listSignals.Add(signal);
                }
                Signalods.SetInvalid(InvalidType.TaskPatient, KeyType.Undefined, _patTo.PatNum); //Ensure anyone viewing Patient tab of new pat gets refreshed.
                Signalods.Insert(listSignals.ToArray());                                         //Refreshes existing tasks in all other tabs.
                //Causes Task area and open Task Edit windows to refresh immediately.  No popups, alright to pass empty lists for listRefreshedTaskNotes and
                //listBlockedTaskLists.
                FormOpenDental.S_HandleRefreshedTasks(listSignals, listPatientTasks.Select(x => x.TaskNum).ToList(), listPatientTasks, new List <TaskNote>()
                                                      , new List <UserOdPref>());
                #endregion
                //Now copy the physical images from the old patient to the new if they are using an AtoZ image share.
                //This has to happen in the UI because the middle tier server might not have access to the image share.
                //If the users are storing images within the database, those images have already been taken care of in the merge method above.
                int fileCopyFailures = 0;
                if (PrefC.AtoZfolderUsed == DataStorageType.LocalAtoZ)
                {
                    #region Copy AtoZ Documents
                    //Move the patient documents within the 'patFrom' A to Z folder to the 'patTo' A to Z folder.
                    //We have to be careful here of documents with the same name. We have to rename such documents
                    //so that no documents are overwritten/lost.
                    string   atoZpath  = ImageStore.GetPreferredAtoZpath();
                    string   atozFrom  = ImageStore.GetPatientFolder(_patFrom, atoZpath);
                    string   atozTo    = ImageStore.GetPatientFolder(_patTo, atoZpath);
                    string[] fromFiles = Directory.GetFiles(atozFrom);
                    if (atozFrom == atozTo)
                    {
                        //Very rarely, two patients have the same image folder.  PatFrom and PatTo both have Documents that point to the same file.  Since we
                        //are about to copy the image file for PatFrom to PatTo's directory and delete the file from PatFrom's directory, we would break the
                        //file reference for PatTo's Document.  In this case, skip deleting the original file, since PatTo's Document still references it.
                        Documents.MergePatientDocuments(_patFrom.PatNum, _patTo.PatNum);
                    }
                    else
                    {
                        foreach (string fileCur in fromFiles)
                        {
                            string fileName     = Path.GetFileName(fileCur);
                            string destFileName = fileName;
                            string destFilePath = ODFileUtils.CombinePaths(atozTo, fileName);
                            if (File.Exists(destFilePath))
                            {
                                //The file being copied has the same name as a possibly different file within the destination a to z folder.
                                //We need to copy the file under a unique file name and then make sure to update the document table to reflect
                                //the change.
                                destFileName = _patFrom.PatNum.ToString() + "_" + fileName;
                                destFilePath = ODFileUtils.CombinePaths(atozTo, destFileName);
                                while (File.Exists(destFilePath))
                                {
                                    destFileName = _patFrom.PatNum.ToString() + "_" + fileName + "_" + DateTime.Now.ToString("yyyyMMddhhmmss");
                                    destFilePath = ODFileUtils.CombinePaths(atozTo, destFileName);
                                }
                            }
                            try {
                                File.Copy(fileCur, destFilePath);                                //Will throw exception if file already exists.
                            }
                            catch (Exception ex) {
                                ex.DoNothing();
                                fileCopyFailures++;
                                continue;                                //copy failed, increment counter and move onto the next file
                            }
                            //If the copy did not fail, try to delete the old file.
                            //We can now safely update the document FileName and PatNum to the "to" patient.
                            Documents.MergePatientDocument(_patFrom.PatNum, _patTo.PatNum, fileName, destFileName);
                            try {
                                File.Delete(fileCur);
                            }
                            catch (Exception ex) {
                                ex.DoNothing();
                                //If we were unable to delete the file then it is probably because someone has the document open currently.
                                //Just skip deleting the file. This means that occasionally there will be an extra file in their backup
                                //which is just clutter but at least the merge is guaranteed this way.
                            }
                        }
                    }
                    #endregion Copy AtoZ Documents
                }                //end if AtoZFolderUsed
                else if (CloudStorage.IsCloudStorage)
                {
                    string atozFrom = ImageStore.GetPatientFolder(_patFrom, "");
                    string atozTo   = ImageStore.GetPatientFolder(_patTo, "");
                    if (atozFrom == atozTo)
                    {
                        //Very rarely, two patients have the same image folder.  PatFrom and PatTo both have Documents that point to the same file.  Since we
                        //are about to copy the image file for PatFrom to PatTo's directory and delete the file from PatFrom's directory, we would break the
                        //file reference for PatTo's Document.  In this case, skip deleting the original file, since PatTo's Document still references it.
                        Documents.MergePatientDocuments(_patFrom.PatNum, _patTo.PatNum);
                    }
                    else
                    {
                        FormProgress FormP = new FormProgress();
                        FormP.DisplayText          = "Moving Documents...";
                        FormP.NumberFormat         = "F";
                        FormP.NumberMultiplication = 1;
                        FormP.MaxVal = 100;                      //Doesn't matter what this value is as long as it is greater than 0
                        FormP.TickMS = 1000;
                        OpenDentalCloud.Core.TaskStateMove state = CloudStorage.MoveAsync(atozFrom
                                                                                          , atozTo
                                                                                          , new OpenDentalCloud.ProgressHandler(FormP.OnProgress));
                        if (FormP.ShowDialog() == DialogResult.Cancel)
                        {
                            state.DoCancel   = true;
                            fileCopyFailures = state.CountTotal - state.CountSuccess;
                        }
                        else
                        {
                            fileCopyFailures = state.CountFailed;
                        }
                    }
                }
                Cursor = Cursors.Default;
                if (fileCopyFailures > 0)
                {
                    MessageBox.Show(Lan.g(this, "Some files belonging to the from patient were not copied.") + "\r\n"
                                    + Lan.g(this, "Number of files not copied") + ": " + fileCopyFailures);
                }
                //Make log entry here not in parent form because we can merge multiple patients at a time.
                SecurityLogs.MakeLogEntry(Permissions.PatientMerge, _patTo.PatNum,
                                          "Patient: " + _patFrom.GetNameFL() + "\r\nPatNum From: " + _patFrom.PatNum + "\r\nPatNum To: " + _patTo.PatNum);
                textPatientIDFrom.Text    = "";
                textPatientNameFrom.Text  = "";
                textPatFromBirthdate.Text = "";
                //This will cause CheckUIState() to disabled the merge button until the user selects a new _patFrom.
                _patFrom = null;
                CheckUIState();
                MsgBox.Show(this, "Patients merged successfully.");
            }            //end MergeTwoPatients
            Cursor = Cursors.Default;
        }
Example #5
0
 private void butDelete_Click(object sender, EventArgs e)
 {
     if (!MsgBox.Show(this, MsgBoxButtons.OKCancel, "Delete?"))
     {
         return;
     }
     if (TaskNoteCur.IsNew)
     {
         DialogResult = DialogResult.Cancel;
         Close();                //Needed because the window is called as a non-modal window.
         return;
     }
     TaskNotes.Delete(TaskNoteCur.TaskNoteNum);
     DialogResult = DialogResult.OK;
     OnEditComplete();   //Signals sent from FormTaskEdit.
     Tasks.TaskEditCreateLog(Permissions.TaskNoteEdit, Lan.g(this, "Deleted note from task"), Tasks.GetOne(TaskNoteCur.TaskNum));
     Close();            //Needed because the window is called as a non-modal window.
 }
Example #6
0
        private void butOK_Click(object sender, EventArgs e)
        {
            if (textNote.Text == "")
            {
                MsgBox.Show(this, "Please enter a note, or delete this entry.");
                return;
            }
            //We need the old datetime to check if the user made any changes.  We overrite TaskNoteCur's date time below so need to get it here.
            DateTime dateTimeNoteOld = TaskNoteCur.DateTimeNote;

            try {
                TaskNoteCur.DateTimeNote = DateTime.Parse(textDateTime.Text);
            }
            catch {
                MsgBox.Show(this, "Please fix date.");
                return;
            }
            if (TaskNoteCur.IsNew)
            {
                TaskNoteCur.Note = textNote.Text;
                TaskNotes.Insert(TaskNoteCur);
                Tasks.TaskEditCreateLog(Permissions.TaskNoteEdit, Lan.g(this, "Added task note"), Tasks.GetOne(TaskNoteCur.TaskNum));
                //This refreshes "new" status for the task as appropriate.
                DataValid.SetInvalidTask(TaskNoteCur.TaskNum, true);               //popup
                DialogResult = DialogResult.OK;
                OnEditComplete();
            }
            else if (TaskNoteCur.Note != textNote.Text || dateTimeNoteOld != TaskNoteCur.DateTimeNote)
            {
                //This refreshes "new" status for the task as appropriate.
                DataValid.SetInvalidTask(TaskNoteCur.TaskNum, true);               //popup
                TaskNoteCur.Note = textNote.Text;
                TaskNotes.Update(TaskNoteCur);
                Tasks.TaskEditCreateLog(Permissions.TaskNoteEdit, Lan.g(this, "Task note changed"), Tasks.GetOne(TaskNoteCur.TaskNum));
                DialogResult = DialogResult.OK;
                OnEditComplete();
            }
            else
            {
                //Intentionally blank, user opened an existing task note and did not change the note but clicked OK.
                //This is effectively equivilent to a Cancel click
                DialogResult = DialogResult.Cancel;
            }
            Close();            //Needed because the window is called as a non-modal window.
        }
        ///<summary>Return false to indicate exit app.  Only called when program first starts up at the beginning of FormOpenDental.PrefsStartup.</summary>
        public bool Convert(string fromVersion, string toVersion, bool isSilent, Form currentForm, bool useDynamicMode)
        {
            FromVersion = new Version(fromVersion);
            ToVersion   = new Version(toVersion);
            if (FromVersion >= new Version("3.4.0") && PrefC.GetBool(PrefName.CorruptedDatabase))
            {
                FormOpenDental.ExitCode = 201;              //Database was corrupted due to an update failure
                if (!isSilent)
                {
                    MsgBox.Show(this, "Your database is corrupted because an update failed.  Please contact us.  This database is unusable and you will need to restore from a backup.");
                }
                return(false);               //shuts program down.
            }
            //There was a 19.3.0 convert method released in the 19.2.3 version.
            //We have to treat 19.3.0 as 19.2.3 so newer convert methods will run.
            if (!ODBuild.IsDebug() && FromVersion.ToString() == "19.3.0.0")
            {
                FromVersion = new Version("19.2.3.0");
                ODException.SwallowAnyException(() => Prefs.UpdateString(PrefName.DataBaseVersion, "19.2.3.0"));
            }
            if (FromVersion == ToVersion)
            {
                return(true);                         //no conversion necessary
            }
            if (FromVersion.CompareTo(ToVersion) > 0) //"Cannot convert database to an older version."
            //no longer necessary to catch it here.  It will be handled soon enough in CheckProgramVersion
            {
                return(true);
            }
            if (FromVersion < new Version("2.8.0"))
            {
                FormOpenDental.ExitCode = 130;              //Database must be upgraded to 2.8 to continue
                if (!isSilent)
                {
                    MsgBox.Show(this, "This database is too old to easily convert in one step. Please upgrade to 2.1 if necessary, then to 2.8.  Then you will be able to upgrade to this version. We apologize for the inconvenience.");
                }
                return(false);
            }
            if (FromVersion < new Version("6.6.2"))
            {
                FormOpenDental.ExitCode = 131;              //Database must be upgraded to 11.1 to continue
                if (!isSilent)
                {
                    MsgBox.Show(this, "This database is too old to easily convert in one step. Please upgrade to 11.1 first.  Then you will be able to upgrade to this version. We apologize for the inconvenience.");
                }
                return(false);
            }
            if (FromVersion < new Version("3.0.1"))
            {
                if (!isSilent)
                {
                    MsgBox.Show(this, "This is an old database.  The conversion must be done using MySQL 4.1 (not MySQL 5.0) or it will fail.");
                }
            }
            if (FromVersion.ToString() == "2.9.0.0" || FromVersion.ToString() == "3.0.0.0" || FromVersion.ToString() == "4.7.0.0")
            {
                FormOpenDental.ExitCode = 190;              //Cannot convert this database version which was only for development purposes
                if (!isSilent)
                {
                    MsgBox.Show(this, "Cannot convert this database version which was only for development purposes.");
                }
                return(false);
            }
            if (FromVersion > new Version("4.7.0") && FromVersion.Build == 0)
            {
                FormOpenDental.ExitCode = 190;              //Cannot convert this database version which was only for development purposes
                if (!isSilent)
                {
                    MsgBox.Show(this, "Cannot convert this database version which was only for development purposes.");
                }
                return(false);
            }
            if (FromVersion >= ConvertDatabases.LatestVersion)
            {
                return(true);               //no conversion necessary
            }
            //Trial users should never be able to update a database.
            if (ODBuild.IsTrial() && PrefC.GetString(PrefName.RegistrationKey) != "") //Allow databases with no reg key to update.  Needed by our conversion department.
            {
                FormOpenDental.ExitCode = 191;                                        //Trial versions cannot connect to live databases
                if (!isSilent)
                {
                    MsgBox.Show(this, "Trial versions cannot connect to live databases.  Please run the Setup.exe in the AtoZ folder to reinstall your original version.");
                }
                return(false);
            }
            string webServiceServerName = PrefC.GetString(PrefName.WebServiceServerName);

            //If the WebServiceServerName name is not set and they are using dynamic mode, continue on to download the binaries in CheckProgramVersion.
            //Or, if they do have the WebServiceServerName set and this is not the computer, continue on to CheckProgramVersion.
            if ((webServiceServerName == "" && useDynamicMode) ||
                (webServiceServerName != "" && !ODEnvironment.IdIsThisComputer(webServiceServerName.ToLower())))
            {
                if (isSilent)
                {
                    FormOpenDental.ExitCode = 141;   //Updates are only allowed from a designated web server
                    return(false);                   //if you are in debug mode and you really need to update the DB, you can manually clear the WebServiceServerName preference.
                }
                //This will be handled in CheckProgramVersion, giving the user option to downgrade or exit program.
                return(true);
            }
            //At this point, the current instance of the program has the ability to execute an upgrade.
            if (RemotingClient.RemotingRole == RemotingRole.ClientWeb)
            {
                FormOpenDental.ExitCode = 140;              //Web client cannot convert database
                if (!isSilent)
                {
                    MsgBox.Show(this, "Web client cannot convert database.  Must be using a direct connection.");
                }
                return(false);
            }
            if (ReplicationServers.ServerIsBlocked())
            {
                FormOpenDental.ExitCode = 150;              //Replication server is blocked from performing updates
                if (!isSilent)
                {
                    MsgBox.Show(this, "This replication server is blocked from performing updates.");
                }
                return(false);
            }
            //If MyISAM and InnoDb mix, then try to fix
            string namesInnodb = "";

            if (DataConnection.DBtype == DatabaseType.MySql)           //not for Oracle
            {
                namesInnodb = InnoDb.GetInnodbTableNames();            //Or possibly some other format.
                int numMyisam = DatabaseMaintenances.GetMyisamTableCount();
                if (namesInnodb != "" && numMyisam > 0)
                {
                    if (!isSilent)
                    {
                        MessageBox.Show(Lan.g(this, "A mixture of database tables in InnoDB and MyISAM format were found.  A database backup will now be made, and then the following InnoDB tables will be converted to MyISAM format: ") + namesInnodb);
                    }
                    if (!Shared.MakeABackup(isSilent, BackupLocation.ConvertScript, false))
                    {
                        Cursor.Current          = Cursors.Default;
                        FormOpenDental.ExitCode = 101;                      //Database Backup failed
                        return(false);
                    }
                    if (!DatabaseMaintenances.ConvertTablesToMyisam())
                    {
                        FormOpenDental.ExitCode = 102;                      //Failed to convert InnoDB tables to MyISAM format
                        if (!isSilent)
                        {
                            MessageBox.Show(Lan.g(this, "Failed to convert InnoDB tables to MyISAM format. Please contact support."));
                        }
                        return(false);
                    }
                    if (!isSilent)
                    {
                        MessageBox.Show(Lan.g(this, "All tables converted to MyISAM format successfully."));
                    }
                    namesInnodb = "";
                }
                if (namesInnodb == "" && numMyisam > 0)             //if all tables are myisam
                //but default storage engine is innodb, then kick them out.
                {
                    if (DatabaseMaintenances.GetStorageEngineDefaultName().ToUpper() != "MYISAM") //Probably InnoDB but could be another format.
                    {
                        FormOpenDental.ExitCode = 103;                                            //Default database .ini setting is innoDB
                        if (!isSilent)
                        {
                            MessageBox.Show(Lan.g(this, "The database tables are in MyISAM format, but the default database engine format is InnoDB. You must change the default storage engine within the my.ini (or my.cnf) file on the database server and restart MySQL in order to fix this problem. Exiting."));
                        }
                        return(false);
                    }
                }
            }
            if (ODBuild.IsDebug())
            {
                if (!isSilent && MessageBox.Show("You are in Debug mode.  Your database can now be converted" + "\r"
                                                 + "from version" + " " + FromVersion.ToString() + "\r"
                                                 + "to version" + " " + ToVersion.ToString() + "\r"
                                                 + "You can click Cancel to skip conversion and attempt to run the newer code against the older database."
                                                 , "", MessageBoxButtons.OKCancel) != DialogResult.OK)
                {
                    return(true);                   //If user clicks cancel, then do nothing
                }
            }
            else              //release
            {
                if (!isSilent && MessageBox.Show(Lan.g(this, "Your database will now be converted") + "\r"
                                                 + Lan.g(this, "from version") + " " + FromVersion.ToString() + "\r"
                                                 + Lan.g(this, "to version") + " " + ToVersion.ToString() + "\r"
                                                 + Lan.g(this, "The conversion works best if you are on the server.  Depending on the speed of your computer, it can be as fast as a "
                                                         + "few seconds, or it can take as long as 10 minutes.")
                                                 + (namesInnodb != "" ? "\r" + Lan.g(this, "The backup tables will be MyISAM format instead of InnoDB.") : "")
                                                 , "", MessageBoxButtons.OKCancel) != DialogResult.OK)
                {
                    return(false);                   //If user clicks cancel, then close the program
                }
            }
            Cursor.Current = Cursors.WaitCursor;
#if !DEBUG
            if (!isSilent)
            {
                if (DataConnection.DBtype != DatabaseType.MySql &&
                    !MsgBox.Show(this, true, "If you have not made a backup, please Cancel and backup before continuing.  Continue?"))
                {
                    return(false);
                }
            }
            if (DataConnection.DBtype == DatabaseType.MySql)
            {
                if (!Shared.MakeABackup(isSilent, BackupLocation.ConvertScript, false))
                {
                    Cursor.Current          = Cursors.Default;
                    FormOpenDental.ExitCode = 101;                  //Database Backup failed
                    return(false);
                }
            }
            //We've been getting an increasing number of phone calls with databases that have duplicate preferences which is impossible
            //unless a user has gotten this far and another computer in the office is in the middle of an update as well.
            //The issue is most likely due to the blocking messageboxes above which wait indefinitely for user input right before upgrading the database.
            //This means that the cache for this computer could be stale and we need to manually refresh our cache to double check
            //that the database isn't flagged as corrupt, an update isn't in progress, or that the database version hasn't changed (someone successfully updated already).
            Prefs.RefreshCache();
            //Now check the preferences that should stop this computer from executing an update.
            if (PrefC.GetBool(PrefName.CorruptedDatabase) ||
                (PrefC.GetString(PrefName.UpdateInProgressOnComputerName) != "" && PrefC.GetString(PrefName.UpdateInProgressOnComputerName) != Environment.MachineName))
            {
                //At this point, the pref "corrupted database" being true means that a computer is in the middle of running the upgrade script.
                //There will be another corrupted database check on start up which will take care of the scenario where this is truly a corrupted database.
                //Also, we need to make sure that the update in progress preference is set to this computer because we JUST set it to that value before entering this method.
                //If it has changed, we absolutely know without a doubt that another computer is trying to update at the same time.
                FormOpenDental.ExitCode = 142;              //Update is already in progress from another computer
                if (!isSilent)
                {
                    MsgBox.Show(this, "An update is already in progress from another computer.");
                }
                return(false);
            }
            //Double check that the database version has not changed.  This check is here just in case another computer has successfully updated the database already.
            Version versionDatabase = new Version(PrefC.GetString(PrefName.DataBaseVersion));
            if (FromVersion != versionDatabase)
            {
                FormOpenDental.ExitCode = 143;              //Database has already been updated from another computer
                if (!isSilent)
                {
                    MsgBox.Show(this, "The database has already been updated from another computer.");
                }
                return(false);
            }
            try {
#endif
            if (FromVersion < new Version("7.5.17"))                     //Insurance Plan schema conversion
            {
                if (isSilent)
                {
                    FormOpenDental.ExitCode = 139;                          //Update must be done manually to fix Insurance Plan Schema
                    Application.Exit();
                    return(false);
                }
                Cursor.Current = Cursors.Default;
                YN InsPlanConverstion_7_5_17_AutoMergeYN = YN.Unknown;
                if (FromVersion < new Version("7.5.1"))
                {
                    FormInsPlanConvert_7_5_17 form = new FormInsPlanConvert_7_5_17();
                    if (PrefC.GetBoolSilent(PrefName.InsurancePlansShared, true))
                    {
                        form.InsPlanConverstion_7_5_17_AutoMergeYN = YN.Yes;
                    }
                    else
                    {
                        form.InsPlanConverstion_7_5_17_AutoMergeYN = YN.No;
                    }
                    form.ShowDialog();
                    if (form.DialogResult == DialogResult.Cancel)
                    {
                        MessageBox.Show("Your database has not been altered.");
                        return(false);
                    }
                    InsPlanConverstion_7_5_17_AutoMergeYN = form.InsPlanConverstion_7_5_17_AutoMergeYN;
                }
                ConvertDatabases.Set_7_5_17_AutoMerge(InsPlanConverstion_7_5_17_AutoMergeYN);                        //does nothing if this pref is already present for some reason.
                Cursor.Current = Cursors.WaitCursor;
            }
            if (!isSilent && FromVersion > new Version("16.3.0") && FromVersion < new Version("16.3.29") && ApptReminderRules.UsesApptReminders())
            {
                //16.3.29 is more strict about reminder rule setup. Prompt the user and allow them to exit the update if desired.
                //Get all currently enabled reminder rules.
                List <bool> listReminderFlags = ApptReminderRules.Get_16_3_29_ConversionFlags();
                if (listReminderFlags?[0] ?? false)                        //2 reminders scheduled for same day of appointment. 1 will be converted to future day reminder.
                {
                    MsgBox.Show(this, "You have multiple appointment reminders set to send on the same day of the appointment. One of these will be converted to send 1 day prior to the appointment.  Please review automated reminder rule setup after update has finished.");
                }
                if (listReminderFlags?[1] ?? false)                        //2 reminders scheduled for future day of appointment. 1 will be converted to same day reminder.
                {
                    MsgBox.Show(this, "You have multiple appointment reminders set to send 1 or more days prior to the day of the appointment. One of these will be converted to send 1 hour prior to the appointment.  Please review automated reminder rule setup after update has finished.");
                }
            }
            if (FromVersion >= new Version("17.3.1") && FromVersion < new Version("17.3.23") && DataConnection.DBtype == DatabaseType.MySql &&
                (Tasks.HasAnyLongDescripts() || TaskNotes.HasAnyLongNotes() || Commlogs.HasAnyLongNotes()))
            {
                if (isSilent)
                {
                    FormOpenDental.ExitCode = 138;                          //Update must be done manually in order to get data loss notification(s).
                    Application.Exit();
                    return(false);
                }
                if (!MsgBox.Show(this, true, "Data will be lost during this update."
                                 + "\r\nContact support in order to retrieve the data from a backup after the update."
                                 + "\r\n\r\nContinue?"))
                {
                    MessageBox.Show("Your database has not been altered.");
                    return(false);
                }
            }
            if (FromVersion >= new Version("3.4.0"))
            {
                Prefs.UpdateBool(PrefName.CorruptedDatabase, true);
            }
            ConvertDatabases.FromVersion = FromVersion;
#if !DEBUG
            //Typically the UpdateInProgressOnComputerName preference will have already been set within FormUpdate.
            //However, the user could have cancelled out of FormUpdate after successfully downloading the Setup.exe
            //OR the Setup.exe could have been manually sent to our customer (during troubleshooting with HQ).
            //For those scenarios, the preference will be empty at this point and we need to let other computers know that an update going to start.
            //Updating the string (again) here will guarantee that all computers know an update is in fact in progress from this machine.
            Prefs.UpdateString(PrefName.UpdateInProgressOnComputerName, Environment.MachineName);
#endif
            //Show a progress window that will indecate to the user that there is an active update in progress. Currently okay to show during isSilent.
            ODProgress.ShowAction(() => ConvertDatabases.InvokeConvertMethods(),
                                  hasMinimize: false,
                                  odEventType: ODEventType.ConvertDatabases);
            Cursor.Current = Cursors.Default;
            if (FromVersion >= new Version("3.4.0"))
            {
                //CacheL.Refresh(InvalidType.Prefs);//or it won't know it has to update in the next line.
                Prefs.UpdateBool(PrefName.CorruptedDatabase, false, true);                      //more forceful refresh in order to properly change flag
            }
            Cache.Refresh(InvalidType.Prefs);
            if (!isSilent)
            {
                MsgBox.Show(this, "Database update successful");
            }
            return(true);

#if !DEBUG
        }

        catch (System.IO.FileNotFoundException e) {
            FormOpenDental.ExitCode = 160;                  //File not found exception
            if (!isSilent)
            {
                MessageBox.Show(e.FileName + " " + Lan.g(this, "could not be found. Your database has not been altered and is still usable if you uninstall this version, then reinstall the previous version."));
            }
            if (FromVersion >= new Version("3.4.0"))
            {
                Prefs.UpdateBool(PrefName.CorruptedDatabase, false);
            }
            return(false);
        }
        catch (System.IO.DirectoryNotFoundException) {
            FormOpenDental.ExitCode = 160;                  //ConversionFiles folder could not be found
            if (!isSilent)
            {
                MessageBox.Show(Lan.g(this, "ConversionFiles folder could not be found. Your database has not been altered and is still usable if you uninstall this version, then reinstall the previous version."));
            }
            if (FromVersion >= new Version("3.4.0"))
            {
                Prefs.UpdateBool(PrefName.CorruptedDatabase, false);
            }
            return(false);
        }
        catch (Exception ex) {
            FormOpenDental.ExitCode = 201;                  //Database was corrupted due to an update failure
            if (!isSilent)
            {
                MessageBox.Show(ex.Message + "\r\n\r\n"
                                + Lan.g(this, "Conversion unsuccessful. Your database is now corrupted and you cannot use it.  Please contact us."));
            }
            //Then, application will exit, and database will remain tagged as corrupted.
            return(false);
        }
#endif
        }
Example #8
0
        private void FillGrid()
        {
            long selectedLinkNum = 0;

            if (gridMain.GetSelectedIndex() != -1)
            {
                selectedLinkNum = (long)gridMain.Rows[gridMain.GetSelectedIndex()].Tag;
            }
            gridMain.BeginUpdate();
            gridMain.Columns.Clear();
            gridMain.Rows.Clear();
            ODGridColumn col = new ODGridColumn("Type", 70);

            gridMain.Columns.Add(col);
            col = new ODGridColumn("Description", 200);
            gridMain.Columns.Add(col);
            ODGridRow row;

            for (int i = 0; i < _jobLinks.Count; i++)
            {
                row = new ODGridRow();
                row.Cells.Add(_jobLinks[i].LinkType.ToString());
                if (_jobLinks[i].LinkType == JobLinkType.Task)
                {
                    Task task = Tasks.GetOne(_jobLinks[i].FKey);
                    if (task == null)                   //task was deleted
                    {
                        continue;
                    }
                    if (task.Descript.Length >= 80)
                    {
                        row.Cells.Add(task.Descript.Substring(0, 80) + "...");
                    }
                    else
                    {
                        row.Cells.Add(task.Descript);
                    }
                }
                else if (_jobLinks[i].LinkType == JobLinkType.Bug)
                {
                    row.Cells.Add("Under Construction");
                }
                else if (_jobLinks[i].LinkType == JobLinkType.Request)
                {
                    row.Cells.Add("Feature Request #" + _jobLinks[i].FKey);
                }
                //else if(_jobLinks[i].LinkType==JobLinkType.Quote) {
                //	JobQuote quote=JobQuotes.GetOne(_jobLinks[i].FKey);
                //	string quoteText="Amount: "+quote.Amount;
                //	if(quote.PatNum!=0) {
                //		Patient pat=Patients.GetPat(quote.PatNum);
                //		quoteText+="\r\nCustomer: "+pat.LName+", "+pat.FName;
                //	}
                //	if(quote.Note!="") {
                //		quoteText+="\r\nNote: "+quote.Note;
                //	}
                //	row.Cells.Add(quoteText);
                //}
                row.Tag = _jobLinks[i].JobLinkNum;
                gridMain.Rows.Add(row);
            }
            gridMain.EndUpdate();
            for (int i = 0; i < gridMain.Rows.Count; i++)
            {
                if ((long)gridMain.Rows[i].Tag == selectedLinkNum)
                {
                    gridMain.SetSelected(i, true);
                }
            }
        }
Example #9
0
        private void FillGrid()
        {
            gridTaskHist.BeginUpdate();
            gridTaskHist.ListGridColumns.Clear();
            GridColumn col = new GridColumn(Lan.g("TableTaskAudit", "Create Date"), 140);

            gridTaskHist.ListGridColumns.Add(col);
            col = new GridColumn(Lan.g("TableTaskAudit", "Edit Date"), 140);
            gridTaskHist.ListGridColumns.Add(col);
            col = new GridColumn(Lan.g("TableTaskAudit", "Editing User"), 80);
            gridTaskHist.ListGridColumns.Add(col);
            col = new GridColumn(Lan.g("TableTaskAudit", "Changes"), 100);
            gridTaskHist.ListGridColumns.Add(col);
            gridTaskHist.ListGridRows.Clear();
            GridRow row;            //Row describes difference between current row and the Next row. Last row will be the last TaskHist compared to the current Task.

            for (int i = 1; i < _listTaskAudit.Count; i++)
            {
                TaskHist taskHistCur  = _listTaskAudit[i - 1];
                TaskHist taskHistNext = _listTaskAudit[i];
                row = new GridRow();
                if (taskHistCur.DateTimeEntry == DateTime.MinValue)
                {
                    row.Cells.Add(_listTaskAudit[i].DateTimeEntry.ToString());
                }
                else
                {
                    row.Cells.Add(taskHistCur.DateTimeEntry.ToString());
                }
                row.Cells.Add(taskHistCur.DateTStamp.ToString());
                long usernum = taskHistCur.UserNumHist;
                if (usernum == 0)
                {
                    usernum = taskHistCur.UserNum;
                }
                row.Cells.Add(Userods.GetUser(usernum).UserName);
                row.Cells.Add(TaskHists.GetChangesDescription(taskHistCur, taskHistNext));
                gridTaskHist.ListGridRows.Add(row);
            }
            //Compare the current task with the last hist entry (Add the "current revision" of the task if necessary.)
            if (_listTaskAudit.Count > 0)
            {
                TaskHist taskHistCur = _listTaskAudit[_listTaskAudit.Count - 1];
                Task     task        = Tasks.GetOne(TaskNumCur);
                if (task != null)
                {
                    TaskHist taskHistNext = new TaskHist(task);
                    row = new GridRow();
                    if (taskHistCur.DateTimeEntry == DateTime.MinValue)
                    {
                        row.Cells.Add(taskHistNext.DateTimeEntry.ToString());
                    }
                    else
                    {
                        row.Cells.Add(taskHistCur.DateTimeEntry.ToString());
                    }
                    row.Cells.Add(taskHistCur.DateTStamp.ToString());
                    long usernum = taskHistCur.UserNumHist;
                    if (usernum == 0)
                    {
                        usernum = taskHistCur.UserNum;
                    }
                    row.Cells.Add(Userods.GetUser(usernum).UserName);
                    row.Cells.Add(TaskHists.GetChangesDescription(taskHistCur, taskHistNext));
                    gridTaskHist.ListGridRows.Add(row);
                }
            }
            gridTaskHist.EndUpdate();
        }