/////////////////////////////////////////////////////////// // UIUserGridLastView.cs // Implementation of Class UIUserGridLastView // CSLA type: Editable Child // Created on: 22-May-2006 // Object design: John // Coded: John 22-May-2006 /////////////////////////////////////////////////////////// using System; using System.Data; using CSLA.Data; using GZTW.Data; using CSLA; using System.Threading; using CSLA.Security; using System.Xml; using System.Text; namespace GZTW.AyaNova.BLL { #pragma warning disable 1591 /// /// Used by user interface to /// hold settings pertaining to a grids last /// filter and order by settings /// /// Replaces UIGridLayout for read only main grids to /// facilitate changeover to saved filters and WBI interface /// /// Used to ensure that the grids appear the same as the /// user last left them in. /// /// [Serializable] public class UIUserGridLastView : BusinessBase { #region Attributes private Guid mUserID; private string mGridKey; private string mViewXML; private Guid mFilterID; //used for UI consumption //generated from xml, not saved to db //Case 637 private DataSet mViewDS; //this was causing hassle so now it should generate ds every time as required #endregion #region Constructor /// /// Private constructor to prevent direct instantiation /// private UIUserGridLastView() { //Set as child object MarkAsChild(); mUserID = CurrentUserID; //Case 637 mViewDS = new DataSet(); mViewXML = ""; //default no filter mFilterID = GridFilter.NoFilterID; } #endregion #region Business properties /// /// User ID number /// public Guid UserID { get { return mUserID; } set { if (mUserID != value) { mUserID = value; MarkDirty(); } } } /// /// /// public string GridKey { get { return mGridKey; } set { if (mGridKey != value) { mGridKey = value; MarkDirty(); } } } /// /// XML fragment used to store grid sql filter criteria, order of columns, /// sort order and visibility of columns. /// /// If a filter ID is non empty when this view is applied to a grid then /// the saved filter takes precedence and the filter portion of the /// xml is not applied to the grid. /// /// If the filter ID is empty then the filter criteria in the XML is used. /// public string ViewXML { get { return mViewXML; } set { if (mViewXML != value) { mViewXML = UIUserGridLastView.ScrubOutContactFieldsFromViewXML(value, mGridKey); MarkDirty(); //Change 03-July-2006 just discovered that if the //dataset is not cleared before the readxml it doesn't apparently //get updated at all //mViewDS.Clear(); //System.IO.StringReader sr = new System.IO.StringReader(mViewXML); //mViewDS.ReadXml(sr); } } } //Case 534 /// /// XML fragment to replace views current /// where item group criteria /// /// (Fragment must contain open and closing WHEREITEMGROUP tags) /// /// Used to programmatically substitute a filter in the last view /// from the UI layer /// (right click context menu on unit or client to view all workorders etc) /// public string SubstituteCriteria { //bugbug - not removing old filters before adding new filter case 770 set { //wait, this could be an issue, below it seems to anticipate this would be a normal condition //I'm going to leave this out for now, prior attempt didn't actually "throw" it so it would have been benign //if (!value.Contains("SubstituteCriteria: Error unexpected view xml (missing WHEREITEMGROUP tags)\r\n" + // "ViewXML:\r\n"+ // mViewXML+ // "Substitute XML:\r\n"+ // value + // "\r\nGridKey:"+this.GridKey + ", UserId: " + this.UserID + // "\r\n---------eot-----" // );//case 3759 int nStart = -1; int nEnd = -1; if (!mViewXML.Contains("WHEREITEMGROUP")) { //Get the position it will go in nStart = mViewXML.IndexOf("", 0); nEnd = nStart; } else { nStart = mViewXML.IndexOf("");//case 770 nEnd = nEnd + 17;//length of } //case 3759 if (nStart == -1 || nEnd == -1) // throw new System.ApplicationException("UIUserGridLastView->SubstituteCriteria: Error could not determine placement of inserted WHEREITEMGROUP tag in view xml:\r\n" + mViewXML); throw new System.ApplicationException("UIUserGridLastView->SubstituteCriteria: Error unexpected view xml\r\n" + "ViewXML:\r\n" + mViewXML + "Substitute XML:\r\n" + value + "\r\nGridKey:" + this.GridKey + ", UserId: " + this.UserID + "\r\n---------eot-----" ); //BUGBUG: this line is throwing an exception for some users (adam tecnica uk) //It needs to be wrapped in a try catch block or tested for sanity //Also what is leading up to it is unclear, perhaps it should trigger a log entry giving as much detail as possible /* 2017-11-16 12:12:55,971 [4864] FATAL AyaNova.Form1 - Unhandled exception System.ArgumentOutOfRangeException: Length cannot be less than zero. Parameter name: length at System.String.Substring(Int32 startIndex, Int32 length) at GZTW.AyaNova.BLL.UIUserGridLastView.set_SubstituteCriteria(String value) at AyaNova.Util.D(Object A, ToolClickEventArgs B) AyaNova.Util.ShowAll_ToolClick(Object sender, ToolClickEventArgs e)" at Infragistics.Win.UltraWinToolbars.ToolBase.OnToolClick(ToolClickEventArgs e) at Infragistics.Win.UltraWinToolbars.UltraToolbarsManager.FireEvent(ToolbarEventIds id, EventArgs e) at Infragistics.Win.UltraWinToolbars.PopupMenuItemUIElement.DoClickProcessing(MouseEventArgs e) at Infragistics.Win.UltraWinToolbars.PopupMenuItemUIElement.OnMouseUp(MouseEventArgs e) at Infragistics.Win.TextUIElementBase.OnMouseUp(MouseEventArgs e) at Infragistics.Win.ControlUIElementBase.ProcessMouseUpHelper(Object sender, MouseEventArgs e) at Infragistics.Win.ControlUIElementBase.ProcessMouseUp(Object sender, MouseEventArgs e) at Infragistics.Win.Utilities.ProcessEvent(Control control, ProcessEvent eventToProcess, EventArgs e) at Infragistics.Win.UltraWinToolbars.PopupControlBase.OnMouseUp(MouseEventArgs e) at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks) at System.Windows.Forms.Control.WndProc(Message& m) at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam) 2017-11-16 12:12:58,654 [4864] WARN AyaNova.Form1 - User opted to abort after exception. Exiting now 2017-11-16 12:12:58,779 [4864] FATAL AyaNova.Form1 - Unhandled exception System.NullReferenceException: Object reference not set to an instance of an object. at AyaNova.MainGrid.B(Object A, MouseEventArgs B) at System.Windows.Forms.Control.OnMouseUp(MouseEventArgs e) at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks) at System.Windows.Forms.Control.WndProc(Message& m) at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam) 2017-11-16 12:12:58,794 [4864] WARN AyaNova.Form1 - User opted to continue after exception 2017-11-16 12:12:58,794 [4864] INFO AyaNova.Form1 - AyaNova has shut down OK 2020-05-08 Michael Mera same issue huge db: 2020-05-08 11:42:19,662 [9944] FATAL AyaNova.Form1 - Unhandled exception System.ArgumentOutOfRangeException: Length cannot be less than zero. Parameter name: length at System.String.Substring(Int32 startIndex, Int32 length) at GZTW.AyaNova.BLL.UIUserGridLastView.set_SubstituteCriteria(String value) at AyaNova.Util.D(Object A, ToolClickEventArgs B) at Infragistics.Win.UltraWinToolbars.ToolBase.OnToolClick(ToolClickEventArgs e) at Infragistics.Win.UltraWinToolbars.UltraToolbarsManager.FireEvent(ToolbarEventIds id, EventArgs e) at Infragistics.Win.UltraWinToolbars.PopupMenuItemUIElement.DoClickProcessing(MouseEventArgs e) at Infragistics.Win.UltraWinToolbars.PopupMenuItemUIElement.OnMouseUp(MouseEventArgs e) at Infragistics.Win.TextUIElementBase.OnMouseUp(MouseEventArgs e) at Infragistics.Win.ControlUIElementBase.ProcessMouseUpHelper(Object sender, MouseEventArgs e) at Infragistics.Win.ControlUIElementBase.ProcessMouseUp(Object sender, MouseEventArgs e) at Infragistics.Win.Utilities.ProcessEvent(Control control, ProcessEvent eventToProcess, EventArgs e) at Infragistics.Win.UltraWinToolbars.PopupControlBase.OnMouseUp(MouseEventArgs e) at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks) at System.Windows.Forms.Control.WndProc(Message& m) at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam) */ //case 3759 for above int StartViewXMLLength = nStart; int EndViewXMLLength = mViewXML.Length - nEnd; if (StartViewXMLLength < 0 || EndViewXMLLength < 0) throw new System.ApplicationException("UIUserGridLastView->SubstituteCriteria: Error bad view xml\r\n" + "ViewXML:\r\n" + mViewXML + "Substitute XML:\r\n" + value + "\r\n=-=-=-=-=-+\r\nStartViewXMLLength:" + StartViewXMLLength.ToString() + ", EndViewXMLLength:" + EndViewXMLLength.ToString() + "\r\nGridKey:" + this.GridKey + ", UserId: " + this.UserID + "\r\n---------eot-----" ); //originally before this case //mViewXML = mViewXML.Substring(0, nStart) + value + mViewXML.Substring(nEnd, mViewXML.Length-nEnd); mViewXML = mViewXML.Substring(0, StartViewXMLLength) + value + mViewXML.Substring(nEnd, EndViewXMLLength); //reset MarkDirty(); //flag as unsaved custom filter FilterID = GridFilter.NoFilterID; } } /// /// Guid of saved filter that was last being used /// by the user when they closed AyaNova /// /// Guid.Empty means the filter is not a saved one /// and so filter settings are customized and should be used /// based on the XML and not the saved filter ID /// public Guid FilterID { get { return mFilterID; } set { if (mFilterID != value) { mFilterID = value; MarkDirty(); } } } /// /// Returns the order by portion of the xml /// as a datatable /// public DataTable ViewOrder { get { if (ViewDS.Tables.Contains("COLUMNITEM")) return ViewDS.Tables["COLUMNITEM"]; else return new DataTable(); } } /// /// returns the filter portion of the xml /// as a datatable object /// public DataTable ViewFilter { get { if (ViewDS.Tables.Contains("WHEREITEMGROUP")) return ViewDS.Tables["WHEREITEMGROUP"]; else return new DataTable(); } } /// /// true if there is a filter contained in the last view object /// public bool HasFilter { get { return (ViewDS.Tables.Contains("WHEREITEMGROUP")); } } /// /// Returns true if the column name in question is filtered /// Used by UI layer /// /// /// public bool IsFiltered(string sColumnName)//case 173 { DataTable dt = ViewFilter; foreach (DataRow dr in dt.Rows) { if (dr["UI"].ToString() == sColumnName) return true; } return false; } //Case 637 private DataSet ViewDS { get { if (string.IsNullOrEmpty(mViewXML)) return new DataSet(); string s = AyaBizUtils.EscapeXml(mViewXML);//case 1724 System.IO.StringReader sr = new System.IO.StringReader(s); DataSet ds = new DataSet(); ds.ReadXml(sr); return ds; } } #endregion #region System.Object overrides public override string ToString() { return "UIUserGridLastView" + mGridKey + mUserID.ToString(); } /// /// public override bool Equals(Object obj) { if (obj == null || GetType() != obj.GetType()) return false; UIUserGridLastView c = (UIUserGridLastView)obj; return ((mUserID == c.mUserID) && (mGridKey == c.mGridKey)); } public override int GetHashCode() { return ("UIUserGridLastView" + mGridKey + mUserID).GetHashCode(); } #endregion #region static methods /// /// Get new object /// /// internal static UIUserGridLastView NewItem(string GridKey) { UIUserGridLastView child = new UIUserGridLastView(); child.GridKey = GridKey; return child; } /// /// GetItem /// /// /// internal static UIUserGridLastView GetItem(SafeDataReader dr) { UIUserGridLastView child = new UIUserGridLastView(); child.Fetch(dr); return child; } /// /// Case 432, remove old contact field sort and filter from view xml /// if possible attempt to sub for new comparable field (email etc) /// internal static string ScrubOutContactFieldsFromViewXML(string sxml, string gridkey) { //short circuit if none of the offending fields are there if (sxml.IndexOf("aContact", StringComparison.InvariantCultureIgnoreCase) == -1 && sxml.IndexOf("aContactPhone.", StringComparison.InvariantCultureIgnoreCase) == -1) return sxml; string sRootObject = gridkey.Replace("List", ""); bool bUnknownObject = false; if (sRootObject != "Vendor" && sRootObject != "Client" && sRootObject != "HeadOffice") bUnknownObject = true; DataSet ds = new DataSet(); System.IO.StringReader sr = new System.IO.StringReader(AyaBizUtils.EscapeXml(sxml)); ds.ReadXml(sr, XmlReadMode.InferSchema); DataTable dtCM = ds.Tables[0]; DataTable dtGroup = new DataTable(); DataTable dtWhere = new DataTable(); if (ds.Tables.Count > 1) dtGroup = ds.Tables[1]; if (ds.Tables.Count > 2) dtWhere = ds.Tables[2]; int nCMRowCount = dtCM.Rows.Count; int nGroupCount = dtGroup.Rows.Count; #region ColumnItems for (int x = 0; x < nCMRowCount; x++) { DataRow dr = dtCM.Rows[x]; if (dr["CM"].ToString().IndexOf("aContact.aEmailAddress", StringComparison.InvariantCultureIgnoreCase) != -1) { if (bUnknownObject) { dtCM.Rows.RemoveAt(x); nCMRowCount--; x--; } else { dr["CM"] = "a" + sRootObject + ".aEmail"; dr["UI"] = "LT_" + sRootObject + "_Label_Email"; } } else if (dr["CM"].ToString().IndexOf("aContact.aFirstName", StringComparison.InvariantCultureIgnoreCase) != -1) { //Always remove dtCM.Rows.RemoveAt(x); nCMRowCount--; x--; } else if (dr["CM"].ToString().IndexOf("aContact.aLastName", StringComparison.InvariantCultureIgnoreCase) != -1) { if (bUnknownObject) { dtCM.Rows.RemoveAt(x); nCMRowCount--; x--; } else {//Sub last name for entire contact field dr["CM"] = "a" + sRootObject + ".aContact"; dr["UI"] = "LT_" + sRootObject + "_Label_Contact"; } } else if (dr["CM"].ToString().IndexOf("aContactPhone.aPhoneNumber", StringComparison.InvariantCultureIgnoreCase) != -1) { if (bUnknownObject) { dtCM.Rows.RemoveAt(x); nCMRowCount--; x--; } else {//Sub last name for entire contact field dr["CM"] = "a" + sRootObject + ".aPhone1"; dr["UI"] = "LT_" + sRootObject + "_Label_Phone1"; } } else if (dr["CM"].ToString().IndexOf("aContactPhone.aPhoneAreaCode", StringComparison.InvariantCultureIgnoreCase) != -1) { //Always remove dtCM.Rows.RemoveAt(x); nCMRowCount--; x--; } } #endregion ColumnItems #region Group (whereitemgroup) for (int x = 0; x < nGroupCount; x++) { DataRow dr = dtGroup.Rows[x]; if (dr["UI"].ToString().IndexOf("LT_Contact_Label_EmailAddress", StringComparison.InvariantCultureIgnoreCase) != -1) { if (bUnknownObject) { dtGroup.Rows.RemoveAt(x); nGroupCount--; x--; } else { dr["UI"] = "LT_" + sRootObject + "_Label_Email"; } } else if (dr["UI"].ToString().IndexOf("LT_Contact_Label_FirstName", StringComparison.InvariantCultureIgnoreCase) != -1) { //Always remove dtGroup.Rows.RemoveAt(x); nGroupCount--; x--; } else if (dr["UI"].ToString().IndexOf("LT_Contact_Label_FirstName", StringComparison.InvariantCultureIgnoreCase) != -1) { if (bUnknownObject) { dtGroup.Rows.RemoveAt(x); nGroupCount--; x--; } else {//Sub last name for entire contact field dr["UI"] = "LT_" + sRootObject + "_Label_Contact"; } } else if (dr["UI"].ToString().IndexOf("LT_ContactPhone_Label_PhoneNumber", StringComparison.InvariantCultureIgnoreCase) != -1) { if (bUnknownObject) { dtGroup.Rows.RemoveAt(x); nGroupCount--; x--; } else {//Sub last name for entire contact field dr["UI"] = "LT_" + sRootObject + "_Label_Phone1"; } } else if (dr["UI"].ToString().IndexOf("LT_ContactPhone_Label_PhoneAreaCode", StringComparison.InvariantCultureIgnoreCase) != -1) { //Always remove dtGroup.Rows.RemoveAt(x); nGroupCount--; x--; } } #endregion Group (whereitemgroup) #region Whereitems int nWhereCount = dtWhere.Rows.Count; for (int x = 0; x < nWhereCount; x++) { DataRow dr = dtWhere.Rows[x]; if (dr["CM"].ToString().IndexOf("aContact.aEmailAddress", StringComparison.InvariantCultureIgnoreCase) != -1) { if (bUnknownObject) { dtWhere.Rows.RemoveAt(x); nWhereCount--; x--; } else { dr["CM"] = "a" + sRootObject + ".aEmail"; dr["UI"] = "LT_" + sRootObject + "_Label_Email"; } } else if (dr["CM"].ToString().IndexOf("aContact.aFirstName", StringComparison.InvariantCultureIgnoreCase) != -1) { //Always remove dtWhere.Rows.RemoveAt(x); nWhereCount--; x--; } else if (dr["CM"].ToString().IndexOf("aContact.aLastName", StringComparison.InvariantCultureIgnoreCase) != -1) { if (bUnknownObject) { dtWhere.Rows.RemoveAt(x); nWhereCount--; x--; } else {//Sub last name for entire contact field dr["CM"] = "a" + sRootObject + ".aContact"; dr["UI"] = "LT_" + sRootObject + "_Label_Contact"; } } else if (dr["CM"].ToString().IndexOf("aContactPhone.aPhoneNumber", StringComparison.InvariantCultureIgnoreCase) != -1) { if (bUnknownObject) { dtWhere.Rows.RemoveAt(x); nWhereCount--; x--; } else {//Sub last name for entire contact field dr["CM"] = "a" + sRootObject + ".aPhone1"; dr["UI"] = "LT_" + sRootObject + "_Label_Phone1"; } } else if (dr["CM"].ToString().IndexOf("aContactPhone.aPhoneAreaCode", StringComparison.InvariantCultureIgnoreCase) != -1) { //Always remove dtWhere.Rows.RemoveAt(x); nWhereCount--; x--; } } #endregion Whereitems StringBuilder sbOut = new StringBuilder(); System.IO.StringWriter sw = new System.IO.StringWriter(sbOut); ds.WriteXml(sw); sw.Close(); return sbOut.ToString(); } #endregion #region DAL DATA ACCESS /// /// Fetch /// /// private void Fetch(SafeDataReader dr) { //UIUserGridLastView fields mGridKey = dr.GetString("aGridKey"); //Important: use the property so that the //dataset get's filled which is in turn //consumed by the UI ViewXML = dr.GetString("aViewXML"); mFilterID = dr.GetGuid("aFilterID"); MarkOld(); } /// /// Update /// /// internal void Update(IDbTransaction tr) { //No need to update if there is nothing changed if (!this.IsDirty) return; //No concurrency check here, maybe need it in future? //shouldn't if users don't log in more than once under //same account though. // If not a new record, check if record was modified //by another user since original retrieval: // if(!IsNew) // DBUtil.CheckSafeToUpdate(this.mModified.Date,this.mID,"PartCategory"); #region Delete if (IsDeleted) { if (!IsNew) { //Delete object and child objects DBCommandWrapper cmDelete = DBUtil.GetCommandFromSQL("DELETE FROM aUIUserGridLastView WHERE aUserID=@UserID AND aGridKey=@GridKey"); cmDelete.AddInParameter("@UserID", DbType.String, mUserID); cmDelete.AddInParameter("@GridKey", DbType.String, mGridKey); DBUtil.DB.ExecuteNonQuery(cmDelete, tr); //----------------------------- } MarkNew(); return; } #endregion #region Add / Update DBCommandWrapper cm = null; if (IsNew)//Add or update? cm = DBUtil.GetCommandFromSQL( "INSERT INTO aUIUserGridLastView (aUserID, aGridKey, " + "aViewXML, aFilterID) VALUES (@UserID, " + "@GridKey,@ViewXML,@FilterID)" ); else cm = DBUtil.GetCommandFromSQL( "UPDATE aUIUserGridLastView SET aUserID=@UserID, aGridKey=@GridKey, " + "aViewXML=@ViewXML,aFilterID=@FilterID " + "WHERE aUserID=@UserID AND aGridKey=@GridKey" ); //UIUserGridLastView fields cm.AddInParameter("@UserID", DbType.Guid, mUserID); cm.AddInParameter("@GridKey", DbType.String, mGridKey); cm.AddInParameter("@ViewXML", DbType.String, mViewXML); cm.AddInParameter("@FilterID", DbType.Guid, mFilterID); DBUtil.DB.ExecuteNonQuery(cm, tr); MarkOld();//db is now synched with object #endregion } #endregion }//end UIUserGridLastView #pragma warning restore 1591 }//end namespace GZTW.AyaNova.BLL