/// <summary> /// Set the activity bin for the row (now set in SQL) /// </summary> public void SetActivityBin( QualifiedNumber resultValueQn, double resultNumericValue, out int activityBin) { UnpivotedAssayResult sRow = this; double val = 0; if (resultNumericValue > 0) // use numeric value if we have it { val = resultNumericValue; } else if (resultValueQn != null && resultValueQn.NumberValue > 0) // otherwise use any qualified number numeric value { val = resultValueQn.NumberValue; } if (val <= 0) { activityBin = 0; // no valid value } else if (Lex.Eq(sRow.ResultTypeConcType, "SP")) { // calc SP activity bin double crc = ConvertSPToCRC(val, sRow.Conc); activityBin = CalcCRCActivityBin(crc); } else // calc CRC activity bin { activityBin = CalcCRCActivityBin(val); } }
public static bool TryParse( string txt, QualifiedNumber qn) { double d; if (txt == null) { return(false); } ParseToTextElements(txt, StaticQnte); qn.Qualifier = StaticQnte.Qualifier; if (NumberEx.DoubleTryParseEx(StaticQnte.NumberValue, out d)) { qn.NumberValue = d; } else { return(false); } // todo: finish parsing stats return(true); }
public static bool TryConvertToInt( object vo, out int iVal) { double dVal; iVal = NullValue.NullNumber; if (vo == null || vo is DBNull) { return(false); } if (vo is int) { iVal = (int)vo; return(true); } if (!QualifiedNumber.TryConvertToDouble(vo, out dVal)) { return(false); } if (dVal > int.MaxValue || dVal < int.MinValue) { return(false); } iVal = Convert.ToInt32(dVal); return(true); }
/// <summary> /// Return rough string version of qualified number /// </summary> /// <returns></returns> public override string ToString() { QualifiedNumber qn = this; string s = ""; if (IsNull) { return(NullValue.NullValueString); } if (!String.IsNullOrEmpty(Qualifier)) { s += Qualifier; } if (NumberValue != QualifiedNumber.NullNumber) { s += NumberValue; } if (qn.NValue > 1 || qn.NValueTested > 1 || // format with sd, n (qn.NValue >= 0 && qn.NValueTested > qn.NValue) || // number tested > n (qn.NumberValue == QualifiedNumber.NullNumber && // also null numbers if some nonzero nvalue (qn.NValue > 0 || qn.NValueTested > 0))) { if (qn.StandardDeviation != QualifiedNumber.NullNumber) { s += ", sd=" + qn.StandardDeviation; } if (qn.StandardError != QualifiedNumber.NullNumber) { s += ", se=" + qn.StandardError; } s += ", n=" + (int)qn.NValue; if (qn.NValueTested > qn.NValue) { s += "/" + (int)qn.NValueTested; } } if (!String.IsNullOrEmpty(qn.TextValue)) { if (s.Length > 0) { s += " "; } s += qn.TextValue; } return(s); }
/// <summary> /// Try to parse qualified number (qualifier, number part only) /// </summary> /// <param name="txt"></param> /// <param name="qn"></param> /// <returns></returns> public static bool TryParse( string txt, out QualifiedNumber qn) { qn = new QualifiedNumber(); bool isValid = TryParse(txt, qn); if (!isValid) { qn = null; } return(isValid); }
/// <summary> /// Custom compact deserialization /// </summary> /// <param name="sa"></param> /// <param name="sai"></param> /// <returns></returns> public static QualifiedNumber Deserialize(string[] sa, int sai) { QualifiedNumber qn = new QualifiedNumber(); qn.Qualifier = DeserializeField(sa[sai + 0], QnModel.Qualifier); qn.NumberValue = DeserializeField(sa[sai + 1], QnModel.NumberValue); qn.StandardDeviation = DeserializeField(sa[sai + 2], QnModel.StandardDeviation); qn.StandardDeviation = DeserializeField(sa[sai + 3], QnModel.StandardError); qn.NValue = DeserializeField(sa[sai + 4], QnModel.NValue); qn.NValueTested = DeserializeField(sa[sai + 5], QnModel.NValueTested); qn.TextValue = DeserializeField(sa[sai + 6], QnModel.TextValue); return(qn); }
/// <summary> /// Clone a qualified number /// </summary> /// <returns></returns> public new QualifiedNumber Clone() { QualifiedNumber qn = (QualifiedNumber)this.MemberwiseClone(); if (qn.MdtExAttr != null) { qn.MdtExAttr = MdtExAttr.Clone(); } if (qn.QnExAttr != null) { qn.QnExAttr = QnExAttr.Clone(); } return(qn); }
/// <summary> /// Convert the object to q QualifiedNumber /// </summary> /// <param name="o"></param> /// <param name="qn"></param> /// <returns></returns> public static bool TryConvertTo( object o, out QualifiedNumber qn) { qn = null; try { qn = ConvertTo(o); return(true); } catch (Exception ex) { return(false); } }
/// <summary> /// Try to convert an object value to a qualified number /// </summary> /// <param name="value"></param> /// <param name="qn"></param> /// <returns></returns> public static bool TryConvert( object value, out QualifiedNumber qn) { if (value is double) { qn = new QualifiedNumber(); qn.NumberValue = (double)value; return(true); } else if (value is float) { qn = new QualifiedNumber(); qn.NumberValue = (float)value; return(true); } else if (value is int) { qn = new QualifiedNumber(); qn.NumberValue = (int)value; return(true); } else if (value is long) { qn = new QualifiedNumber(); qn.NumberValue = (long)value; return(true); } else if (value is string) { qn = new QualifiedNumber(); qn.TextValue = (string)value; return(true); } else { qn = null; return(false); } }
/// <summary> /// Set result value conditional format color based on bin value /// </summary> public void SetResultValueBackColor( QualifiedNumber resultValue, int activityBin) { if (activityBin < 0) { return; // just return if bin not defined } QualifiedNumber v = resultValue; if (v == null) { return; } v.BackColor = CalculateBinColor(activityBin); return; }
/// <summary> /// Binary Deserialize /// </summary> /// <param name="br"></param> /// <returns></returns> public static QualifiedNumber DeserializeBinary(BinaryReader br) { QualifiedNumber qn = new QualifiedNumber(); MobiusDataType.DeserializeBinary(br, qn); if (br.ReadBoolean()) { qn.Qualifier = br.ReadString(); } if (br.ReadBoolean()) { qn.NumberValue = br.ReadDouble(); } if (br.ReadBoolean()) { qn.StandardDeviation = br.ReadDouble(); } if (br.ReadBoolean()) { qn.StandardError = br.ReadDouble(); } if (br.ReadBoolean()) { qn.NValue = br.ReadInt32(); } if (br.ReadBoolean()) { qn.NValueTested = br.ReadInt32(); } if (br.ReadBoolean()) { qn.TextValue = br.ReadString(); } return(qn); }
/// <summary> /// Match QualifiedNumber value /// </summary> /// <param name="rules"></param> /// <param name="value"></param> /// <returns></returns> public static CondFormatRule Match( CondFormat condFormat, QualifiedNumber value) { if (value.IsNull) { return(Match(condFormat, NullValue.NullNumber)); } else { return(Match(condFormat, value.NumberValue)); } // else if (MetaColumn.IsNumericMetaColumnType(condFormat.ColumnType)) // { // return Match(condFormat, value.NumberValue); // } // else return Match(condFormat, value.TextValue); }
/// <summary> /// Format a basic qualified number with qualifier and value /// </summary> /// <param name="qn"></param> /// <param name="displayFormat"></param> /// <param name="decimals"></param> /// <returns></returns> public string Format( ColumnFormatEnum displayFormat, int decimals) { string result; QualifiedNumber qn = this; if (qn.Qualifier == null) { qn.Qualifier = ""; } if (qn.TextValue == null) { qn.TextValue = ""; } if (qn.Hyperlink == null) { qn.Hyperlink = ""; } if (qn.NumberValue == NullValue.NullNumber) { if (qn.NValue != NullValue.NullNumber) { return("ND"); // some NValue, return not determined } else { return(qn.TextValue); } } result = FormatNumber(qn.NumberValue, displayFormat, decimals); if (qn.Qualifier != "") { result = qn.Qualifier + result; } return(result); }
/// <summary> /// Try to convert an object to a double value /// </summary> /// <param name="vo"></param> /// <param name="dVal"></param> /// <returns></returns> public static bool TryConvertToDouble( object vo, out double dVal) { string qualifier; if (!QualifiedNumber.TryConvertToQualifiedDouble(vo, out dVal, out qualifier)) { return(false); } if (String.IsNullOrEmpty(qualifier)) { return(true); // if no qualifier then ok } else // failed { dVal = NullValue.NullNumber; return(false); } }
/// <summary> /// Convert object to a MobiusDataType /// </summary> /// <param name="o"></param> /// <param name="type"></param> /// <returns></returns> public static MobiusDataType ConvertToMobiusDataType( MetaColumnType type, Object o) { switch (type) { case MetaColumnType.Integer: case MetaColumnType.Number: case MetaColumnType.DictionaryId: return(NumberMx.ConvertTo(o)); case MetaColumnType.QualifiedNo: return(QualifiedNumber.ConvertTo(o)); case MetaColumnType.String: case MetaColumnType.MolFormula: case MetaColumnType.Hyperlink: case MetaColumnType.Html: case MetaColumnType.Binary: return(StringMx.ConvertTo(o)); case MetaColumnType.Date: return(DateTimeMx.ConvertTo(o)); case MetaColumnType.CompoundId: return(CompoundId.ConvertTo(o)); case MetaColumnType.Structure: return(MoleculeMx.ConvertTo(o)); case MetaColumnType.Image: return(ImageMx.ConvertTo(o)); // assume text is dblink default: throw new Exception("Unrecognized data type: " + type); } }
/// <summary> /// General constructor from an object /// </summary> /// <param name="o"></param> public NumberMx( object o) { if (NullValue.IsNull(o)) { return; } if (o is int) { Value = (int)o; } else if (o is double) { Value = (double)o; } else if (o is string) { if (!double.TryParse((string)o, out Value)) { throw new Exception("Invalid number: " + (string)o); } } else if (o is QualifiedNumber) { QualifiedNumber qn = o as QualifiedNumber; Value = qn.NumberValue; ((MobiusDataType)o).MemberwiseCopy(this); // copy base values } else { throw new InvalidCastException(o.GetType().ToString()); } }
///////////////////////////////////////////////////////////////// //////////////////////////// Methods //////////////////////////// ///////////////////////////////////////////////////////////////// /// <summary> /// Create a Mobius data type based on the supplied MetaColumn type /// </summary> /// <param name="type"></param> /// <returns></returns> public static MobiusDataType New( MetaColumnType type) { MobiusDataType o; if (type == MetaColumnType.Integer) { o = new NumberMx(); } else if (type == MetaColumnType.Number) { o = new NumberMx(); } else if (type == MetaColumnType.QualifiedNo) { o = new QualifiedNumber(); } else if (type == MetaColumnType.String) { o = new StringMx(); } else if (type == MetaColumnType.Date) { o = new DateTimeMx(); } else if (type == MetaColumnType.Binary) { o = new StringMx(); } else if (type == MetaColumnType.CompoundId) { o = new CompoundId(); } else if (type == MetaColumnType.Structure) { o = new MoleculeMx(); } else if (type == MetaColumnType.MolFormula) { o = new StringMx(); } else if (type == MetaColumnType.Image) { o = new ImageMx(); } else if (type == MetaColumnType.DictionaryId) { o = new NumberMx(); } else if (type == MetaColumnType.Hyperlink) { o = new StringMx(); } else if (type == MetaColumnType.Html) { o = new StringMx(); } else { throw new Exception("Unrecognized data type: " + type); } return(o); }
/// <summary> /// Custom compact Deserialization of MobiusDataType /// </summary> /// <returns></returns> public static MobiusDataType Deserialize(string[] sa) { int sai; MobiusDataType mdt = null; char type = sa[0][0]; sai = 5; // first array entry for specific subclass switch (type) { case 'M': // ChemicalStructure (Molecule) mdt = MoleculeMx.Deserialize(sa, sai); break; case 'C': // CompoundId mdt = CompoundId.Deserialize(sa, sai); break; case 'D': // DateTimeEx mdt = DateTimeMx.Deserialize(sa, sai); break; case 'I': // ImageEx mdt = ImageMx.Deserialize(sa, sai); break; case 'N': //NumberEx mdt = NumberMx.Deserialize(sa, sai); break; case 'Q': // QualifiedNumber mdt = QualifiedNumber.Deserialize(sa, sai); break; case 'S': // StringEx mdt = StringMx.Deserialize(sa, sai); break; default: throw new Exception("Unexpected MobiusDataType: " + type); } if (!Lex.IsNullOrEmpty(sa[1])) { mdt.BackColor = Color.FromArgb(int.Parse(sa[1])); } if (!Lex.IsNullOrEmpty(sa[2])) { mdt.ForeColor = Color.FromArgb(int.Parse(sa[2])); } if (!Lex.IsNullOrEmpty(sa[3])) { mdt.DbLink = sa[3]; } if (!Lex.IsNullOrEmpty(sa[4])) { mdt.Hyperlink = sa[4]; } return(mdt); }
/// <summary> /// Compare two values (IComparable.CompareTo) /// </summary> /// <param name="o"></param> /// <returns></returns> public override int CompareTo( object o) { if (o == null) { return(1); } StringMx sx = this; if (o is StringMx) { StringMx sx2 = o as StringMx; if (sx.IsNull && sx2.IsNull) { return(0); } else if (!sx.IsNull && sx2.IsNull) { return(1); } else if (sx.IsNull && !sx2.IsNull) { return(-1); } else { return(string.Compare(sx.Value, sx2.Value, true)); // compare ignoring case } } else if (o is QualifiedNumber) { QualifiedNumber qn = o as QualifiedNumber; if (sx.IsNull && qn.IsNull) { return(0); } else if (!sx.IsNull && qn.IsNull) { return(1); } else if (sx.IsNull && !qn.IsNull) { return(-1); } return(string.Compare(this.Value, qn.TextValue, true)); // compare ignoring case } else if (o is string) { string s = (string)o; if (sx.IsNull) { if (o == null) { return(0); } else { return(-1); } } else { return(string.Compare(sx.Value, s, true)); } } else { throw new Exception("Can't compare a " + GetType().Name + " to a " + o.GetType()); } }
/// <summary> /// Write out the values for a data row /// </summary> /// <param name="dr"></param> /// <param name="qtMap"></param> /// <param name="tw"></param> /// <param name="ep"></param> /// <param name="outputNValues"></param> /// <param name="nValueMetaColumns"></param> /// <param name="noDataForTable"></param> /// <param name="ti"></param> /// <param name="keyValueForRow"></param> void WriteRowValues( object[] dr, QueryTableVoMap qtMap, SpotfireDataFileTableWriter tw, ExportParms ep, bool outputNValues, HashSet <MetaColumn> nValueMetaColumns, bool noDataForTable = false, int ti = 0, string keyValueForRow = "") { QueryColumn qc; MetaColumn mc; SpotfireDataFileValueType sdfType; QualifiedNumber qn; object vo, vo2; double dVal; string txt; for (int fi = 0; fi < qtMap.SelectedColumns.Count; fi++) { qc = qtMap.SelectedColumns[fi]; mc = qc.MetaColumn; sdfType = (SpotfireDataFileValueType)qc.SpotfireExportType; if (noDataForTable && ti == 0 && qc.IsKey) // if this is the root table and no data then supply the row key value { vo = keyValueForRow; noDataForTable = false; // now have data } if (noDataForTable) { vo = null; } else { vo = dr[qc.VoPosition]; } bool isNull = NullValue.IsNull(vo); if (isNull && (mc.DataType != MetaColumnType.QualifiedNo)) // write null value (unless QN which may require multiple value writes) { WriteValue(tw, sdfType, null); } else if (mc.DataType == MetaColumnType.Structure) { if (vo is MoleculeMx) { string molString = GetMoleculeString(vo, ep.ExportStructureFormat); WriteValue(tw, sdfType, molString); } else { vo2 = MobiusDataType.ConvertToPrimitiveValue(vo, mc); WriteValue(tw, sdfType, vo2); } } else if (mc.DataType == MetaColumnType.QualifiedNo) // write 1-3 values for Qualified number { // Output a split QN if (QnSubcolumns.IsSplitFormat(ep.QualifiedNumberSplit)) { if (vo is QualifiedNumber && !isNull) // regular QN { qn = (QualifiedNumber)vo; WriteValue(tw, SpotfireDataFileValueType.String, qn.Qualifier); // qualifier WriteValue(tw, SpotfireDataFileValueType.Double, qn.NumberValue); if (outputNValues && nValueMetaColumns.Contains(mc)) { if (NullValue.IsNull(qn.NValueTested)) { WriteValue(tw, SpotfireDataFileValueType.Int, null); // number in calc } else { WriteValue(tw, SpotfireDataFileValueType.Int, qn.NValueTested); } } } else if (!isNull) // non-qn { WriteValue(tw, SpotfireDataFileValueType.String, null); // qualifier if (QualifiedNumber.TryConvertToDouble(vo, out dVal)) { WriteValue(tw, SpotfireDataFileValueType.Double, dVal); } else { WriteValue(tw, SpotfireDataFileValueType.Double, null); } if (outputNValues && nValueMetaColumns.Contains(mc)) { WriteValue(tw, SpotfireDataFileValueType.Int, null); // N value } } else // null value { WriteValue(tw, SpotfireDataFileValueType.String, null); // qualifier WriteValue(tw, SpotfireDataFileValueType.Double, null); // value if (outputNValues && nValueMetaColumns.Contains(mc)) { WriteValue(tw, SpotfireDataFileValueType.Int, null); // N value } } } // Output a non-split (combined) QN else // combined { if (isNull) { WriteValue(tw, SpotfireDataFileValueType.String, null); } else if (vo is QualifiedNumber && !isNull) // regular QN { qn = (QualifiedNumber)vo; txt = qn.Format(qc, false, mc.Format, mc.Decimals, ep.QualifiedNumberSplit, false); WriteValue(tw, SpotfireDataFileValueType.String, txt); } else if (!isNull) // non-qn { txt = vo.ToString(); WriteValue(tw, SpotfireDataFileValueType.String, txt); } else // null value { WriteValue(tw, SpotfireDataFileValueType.String, null); } } } else // write other types as primitive value for now { vo2 = MobiusDataType.ConvertToPrimitiveValue(vo, mc); WriteValue(tw, sdfType, vo2); } } // col loop return; }
/// <summary> /// Deserialize a single value object /// </summary> /// <param name="ba"></param> /// <returns></returns> public static object ReadBinaryItem( BinaryReader br) { object vo = null; VoDataType voType = (VoDataType)br.ReadByte(); switch (voType) { case VoDataType.Null: return(null); case VoDataType.DbNull: return(DBNull.Value); case VoDataType.Byte: return(br.ReadByte()); case VoDataType.Int16: return(br.ReadInt16()); case VoDataType.Int32: return(br.ReadInt32()); case VoDataType.Int64: return(br.ReadInt64()); case VoDataType.Float: return(br.ReadSingle()); case VoDataType.Double: return(br.ReadDouble()); case VoDataType.Char: return(br.ReadChar()); case VoDataType.String: return(br.ReadString()); case VoDataType.DateTime: return(new DateTime(br.ReadInt64())); case VoDataType.CompoundId: return(CompoundId.DeserializeBinary(br)); case VoDataType.NumberMx: return(NumberMx.DeserializeBinary(br)); case VoDataType.QualifiedNo: return(QualifiedNumber.DeserializeBinary(br)); case VoDataType.StringMx: return(StringMx.DeserializeBinary(br)); case VoDataType.DateTimeMx: return(DateTimeMx.DeserializeBinary(br)); case VoDataType.ImageMx: return(ImageMx.DeserializeBinary(br)); case VoDataType.ChemicalStructure: return(MoleculeMx.DeserializeBinary(br)); default: throw new Exception("Unrecognized type: " + voType); } }
/// <summary> /// Convert to just a double value and optional qualifier /// </summary> /// <param name="vo"></param> /// <param name="dVal"></param> /// <param name="qualifier"></param> /// <returns></returns> public static bool TryConvertToQualifiedDouble( object vo, out double dVal, out string qualifier) { QualifiedNumber qn; string s = null; dVal = NullValue.NullNumber; qualifier = null; if (vo == null || vo is DBNull || NullValue.IsNull(vo)) { return(false); } qualifier = ""; // provide a blank qualifier if not null if (vo is double) { dVal = (double)vo; } else if (vo is float) { dVal = (float)vo; } else if (vo is decimal) { dVal = decimal.ToDouble((decimal)vo); } else if (vo is QualifiedNumber) { qn = (QualifiedNumber)vo; dVal = qn.NumberValue; if (!String.IsNullOrWhiteSpace(qn.Qualifier)) { qualifier = qn.Qualifier; } } else if (vo is NumberMx) { NumberMx nmx = (NumberMx)vo; dVal = nmx.NumericValue; } else if (vo is int) { dVal = (int)vo; } else if (vo is Int16) { dVal = (Int16)vo; } else if (vo is Int64) { dVal = (Int64)vo; } else if (vo is byte) { dVal = (byte)vo; } else // try to convert to number { s = vo.ToString(); if (QualifiedNumber.TryParse(s, out qn)) { dVal = qn.NumberValue; if (!String.IsNullOrWhiteSpace(qn.Qualifier)) { qualifier = qn.Qualifier; } } else { return(false); // null } } return(true); }
/// <summary> /// Sort a dataset /// </summary> /// <param name="results">Data to sort</param> /// <param name="sortColumns">Columns to sort on</param> /// <param name="query">Query information with vo positions of sort cols</param> /// <param name="keyValueVoPos">Index of added key value</param> /// <param name="ResultKeys">Ordered keys are returned here</param> /// <returns></returns> /// public List <object[]> Sort( List <object[]> results, List <SortColumn> sortColumns, Query query, int keyValueVoPos, out List <string> ResultKeys) { object [] vo, vo2; int qti, ri, ti, sci, i1, i2, i3; SortItem currentVal = null; // current top composite value (high or low) for current key object value; object [] sourceVo, destVo; string key; SortItem sItem = null, sItem2; int keyOffset = 0; // pk is stored in first element of vo and must be offset ValidateSortColumns(sortColumns); // Get array of sort columns associated with each metatable. This will be // used in the sort routine to do the local sorts in the context of // each table bool[][] mtSortCols = new bool[query.Tables.Count][]; MetaTableSortItems mtsi; int mtsiIdx; int firstQtWithSorting = -1; for (sci = 0; sci < sortColumns.Count; sci++) { QueryColumn qc = sortColumns[sci].QueryColumn; for (qti = 0; qti < query.Tables.Count; qti++) { // if (Query.Tables[qti] == qc.QueryTable) break; // (fails for preview) if (Lex.Eq((query.Tables[qti]).MetaTable.Name, qc.QueryTable.MetaTable.Name)) { break; // todo: properly handle when same metatable in query multiple times } } if (qti >= query.Tables.Count) { throw new Exception("Sort column not found in table"); } if (mtSortCols[qti] == null) // allocate array first time { mtSortCols[qti] = new bool[sortColumns.Count]; } mtSortCols[qti][sci] = true; if (firstQtWithSorting < 0) { firstQtWithSorting = qti; } } MultiColumnSortComparer sortComp = // sort including context of 1st table with sorting new MultiColumnSortComparer(sortColumns, mtSortCols[firstQtWithSorting]); // Build the array of values to be sorted. Each element of the array consists of // one or more primary values (i.e. the max or min value for each compound id // depending on the SortDirection for the column), the compound id and // one or more secondary values (i.e. the actual value for the sort key for that row) string currentKey = ""; int firstRowForKey = -1, rowsForKey; List <object> sArray = new List <object>(); object[] voResults = null; for (ri = 0; ri < results.Count; ri++) { vo = (object [])results[ri]; key = (string)vo[keyValueVoPos]; sItem = new SortItem(); sItem.SortValue = new IComparable[sortColumns.Count]; sItem.SortValueB = new IComparable[sortColumns.Count]; sArray.Add(sItem); sItem.Key = key; sItem.TupleIndex = ri; for (sci = 0; sci < sortColumns.Count; sci++) { // copy the primary & secondary values from result buffer into sort value array QueryColumn qc = sortColumns[sci].QueryColumn; SortOrder direction = sortColumns[sci].Direction; if (qc.IsKey) // if key be sure to get non-null value { sItem.SortValue[sci] = sItem.SortValueB[sci] = key; } else // copy non-key values { object o = null; if (qc.VoPosition >= 0 && qc.VoPosition < vo.Length) // be sure in range { o = vo[qc.VoPosition]; // get primitive or Mobius data type } else if (NullValue.IsNull(o)) { o = null; } else if (o is MobiusDataType) // convert Mobius types to a comparable primitive type { if (o is NumberMx) { o = (o as NumberMx).Value; } else if (o is QualifiedNumber) { QualifiedNumber qn = o as QualifiedNumber; if (MetaColumn.IsNumericMetaColumnType(qc.MetaColumn.DataType)) { o = qn.NumberValue; } else if (qc.MetaColumn.DataType == MetaColumnType.String) { o = qn.TextValue; } else { o = qn.NumberValue; // shouldn't happen } } else if (o is StringMx) { o = (o as StringMx).Value; } else if (o is DateTimeMx) { o = (o as DateTimeMx).Value; } else if (o is CompoundId) { o = (o as CompoundId).Value; } } else if (o is byte || o is sbyte || // convert all numbers to doubles so they compare properly (e.g. int that has cond formatting NumberMx values for some rows) o is Int16 || o is Int32 || o is Int64 || o is float || o is decimal) { o = Convert.ToDouble(o); } if (!(o is IComparable)) { o = null; // be sure it's a IComparable } sItem.SortValue[sci] = sItem.SortValueB[sci] = (IComparable)o; } } if (key != null && key != currentKey) // new key value { firstRowForKey = ri; currentKey = key; currentVal = sItem; } else // another tuple for same key { if (sortComp.CompareSortItems(currentVal, sItem) > 0) // new primary value? { currentVal = sItem; for (i1 = firstRowForKey; i1 < ri; i1++) { // reset primary value for preceeding rows for this key to the value of this row sItem2 = (SortItem)sArray[i1]; for (sci = 0; sci < sortColumns.Count; sci++) { sItem2.SortValue[sci] = currentVal.SortValue[sci]; } } } else // copy current primary values to this sort item { for (sci = 0; sci < sortColumns.Count; sci++) { sItem.SortValue[sci] = currentVal.SortValue[sci]; } } } } // Do the first sort which is overall for key order & relative for // first table with sort columns sArray.Sort(sortComp); // Reorder arraylist of raw tuples according to initial search results List <object[]> newResults = new List <object[]>(results.Count); for (ri = 0; ri < sArray.Count; ri++) { sItem = (SortItem)sArray[ri]; newResults.Add(results[sItem.TupleIndex]); } // Setup range in Vo for each query table and its key List <SortTableData> std = new List <SortTableData>(); foreach (QueryTable qt0 in query.Tables) { SortTableData st = new SortTableData(); std.Add(st); foreach (QueryColumn qc0 in qt0.QueryColumns) { MetaColumn mc = qc0.MetaColumn; if (mc.IsKey) { st.KeyColPos = qc0.VoPosition; } if (qc0.VoPosition >= 0 && st.FirstColumn < 0) { st.FirstColumn = qc0.VoPosition; } if (qc0.Selected) { st.SelectCount++; } } } // Do table-relative sort for other tables with sort fields ArrayList CopyBuf = new ArrayList(); // used for copying int voLen = 0; // length of vo if (results != null && results.Count > 0 && results[0] != null) { voLen = ((object [])results[0]).Length; } for (ti = 0; ti < std.Count; ti++) // check all tables { int voTablePos = std[ti].FirstColumn; // +std[ti].KeyColPos + keyOffset; // position of first element of vo for table int voTableLen = std[ti].SelectCount; if (ti == firstQtWithSorting) { continue; // did this table first } else if (mtSortCols[ti] == null) { continue; // no sorting on this one } sortComp = // proper sort comparer for this table new MultiColumnSortComparer(sortColumns, mtSortCols[ti]); sArray.Sort(sortComp); // re-sort original results for this table currentKey = ""; firstRowForKey = -1; rowsForKey = 0; for (ri = 0; ri <= sArray.Count; ri++) // reorder table vo entries for new results { if (ri < sArray.Count) { sItem = (SortItem)sArray[ri]; vo = (object [])results[sItem.TupleIndex]; // address the vo key = (string)vo[keyValueVoPos]; } else { key = "<end>"; // past end of data, force copy back of last chunk } if (key != null && key != currentKey) // new key value { if (firstRowForKey >= 0) // anything to copy back { for (i1 = 0; i1 < rowsForKey; i1++) { // copy back to results buffer in proper order sourceVo = (Object[])CopyBuf[i1]; destVo = (Object[])newResults[firstRowForKey + i1]; Array.Copy(sourceVo, voTablePos, destVo, voTablePos, voTableLen); } } if (ri >= sArray.Count) { break; // really done? } currentKey = key; firstRowForKey = ri; // first row in newResults for the key rowsForKey = 0; } if (CopyBuf.Count < rowsForKey + 1) // be sure copy buffer big enough { CopyBuf.Add(new object[voLen]); } sourceVo = (Object[])results[sItem.TupleIndex]; // copy from original results row to buffer destVo = (Object[])CopyBuf[rowsForKey]; Array.Copy(sourceVo, voTablePos, destVo, voTablePos, voTableLen); rowsForKey++; } // end of loop on results entries } // end of loop on query tables // For each key shift non-null metatable data to top of section for key ResultKeys = new List <string>(); // reorder result keys also currentKey = ""; for (ri = 0; ri < newResults.Count; ri++) { vo = (object [])newResults[ri]; key = (string)vo[keyValueVoPos]; if (key != null && key != currentKey) // new key value { firstRowForKey = ri; currentKey = key; ResultKeys.Add(key); } //else // another row for key, shift up data as needed to fill gaps { if (query.Tables.Count <= 1) { continue; // only need to do if more than one table } for (ti = 0; ti < std.Count; ti++) // check all tables (sorted tables should be ok except for root table is sorted on key { int voTablePos = std[ti].FirstColumn; // +std[ti].KeyColPos + keyOffset; // position of first element of vo for table int voTableLen = std[ti].SelectCount; if (NullValue.IsNull(vo[voTablePos])) { continue; // skip if null data for this table (i.e. key is null) } for (i2 = firstRowForKey; i2 < ri; i2++) // look for empty slot { vo2 = (object [])newResults[i2]; object o = vo2[voTablePos]; if (!NullValue.IsNull(o)) { continue; // already full } Array.Copy(vo, voTablePos, vo2, voTablePos, voTableLen); Array.Clear(vo, voTablePos, voTableLen); break; } } } } return(newResults); // substitute new ordered set of results }
/// <summary> /// Format qualified number /// </summary> /// <param name="qn"></param> /// <param name="qc"></param> /// <param name="mergedField"></param> /// <param name="displayFormat"></param> /// <param name="decimals"></param> /// <param name="qnFormat"></param> /// <param name="outputDest"></param> /// <returns></returns> public string Format( QueryColumn qc, bool mergedField, ColumnFormatEnum displayFormat, int decimals, QnfEnum qnFormat, OutputDest outputDest) { string result, uri, href, txt, tok; result = ""; QualifiedNumber qn = this; MetaColumn mc = qc.MetaColumn; if (qn.Qualifier == null) { qn.Qualifier = ""; } if (qn.TextValue == null) { qn.TextValue = ""; } if (qn.Hyperlink == null) { qn.Hyperlink = ""; } if (QnSubcolumns.IsCombinedFormat(qnFormat)) // normal combined number { if (qn.NumberValue == NullValue.NullNumber && qn.NValue == NullValue.NullNumber && qn.NValueTested == NullValue.NullNumber && qn.TextValue == "") { // null value result = NullValueString; if (outputDest == OutputDest.Html && (NullValueString == "" || NullValueString == " ")) { result = "<br>"; // html blank } return(result); } result = qn.Format(displayFormat, decimals); if (qn.NValue > 1 || qn.NValueTested > 1 || // format with sd, n (qn.NValue >= 0 && qn.NValueTested > qn.NValue) || // number tested > n (qn.NumberValue == NullValue.NullNumber && // also null numbers if some nonzero nvalue (qn.NValue > 0 || qn.NValueTested > 0))) { txt = ""; if (qn.NValue > 1 && (qnFormat & QnfEnum.StdDev) != 0 && // include sd (qn.StandardDeviation != NullValue.NullNumber || qn.StandardError != NullValue.NullNumber)) { // format standard deviation if ((qnFormat & QnfEnum.DisplayStdDevLabel) != 0) { txt += "sd="; } if (qn.StandardDeviation == NullValue.NullNumber) // calc sd from se if don't have { qn.StandardDeviation = qn.StandardError * Math.Sqrt(qn.NValue); } txt += FormatNumber(qn.StandardDeviation, displayFormat, decimals); } if (qn.NValue > 1 && (qnFormat & QnfEnum.StdErr) != 0 && // include se (qn.StandardError != NullValue.NullNumber || qn.StandardDeviation != NullValue.NullNumber)) { // format standard error if (txt != "") { txt += ", "; } if ((qnFormat & QnfEnum.DisplayStdErrLabel) != 0) { txt += "se="; } txt += FormatNumber(qn.StandardError, displayFormat, decimals); } if (qn.NValue != NullValue.NullNumber && (qnFormat & QnfEnum.NValue) != 0) { // format n value if (txt != "") { txt += ", "; } if ((qnFormat & QnfEnum.DisplayNLabel) != 0) { txt += "n="; } txt += qn.NValue.ToString(); if (qn.NValueTested != NullValue.NullNumber && qn.NValueTested != qn.NValue) { txt += "/" + qn.NValueTested.ToString(); // add number tested if different } } if (txt != "") { result += " (" + txt + ")"; // build complete string } } if (qn.DbLink != null && qn.DbLink != "" && qn.DbLink != "." && !mergedField && // do we have an associated resultId (outputDest == OutputDest.WinForms || outputDest == OutputDest.Html)) { uri = qn.FormatHyperlink(qc); //if (outputDest == OutputDest.Grid) // store link info in separate field // qn.Hyperlink = uri; //else if (outputDest == OutputDest.Html) // build full html tag //{ if (uri != "") { result = result = "<a href=" + Lex.Dq(uri) + ">" + result + "</a>"; } //} } } // Format one piece of a split qualified number else if ((qnFormat & QnfEnum.Qualifier) != 0) // qualifier { result = qn.Qualifier; } else if ((qnFormat & QnfEnum.NumericValue) != 0) // basic number { if (qn.NumberValue != NullValue.NullNumber) { result = FormatNumber(qn.NumberValue, displayFormat, decimals); } else { result = null; } //else (obsolete, don't output any text values into numeric column, add option for separate column later) //{ // if (qn.NValue != NullValue.NullNumber) // result = "ND"; // some NValue, return not determined // else result = qn.TextValue; // return any text value //} } else if ((qnFormat & QnfEnum.StdDev) != 0) // standard deviation { if (qn.StandardDeviation != NullValue.NullNumber) { result = FormatNumber(qn.StandardDeviation, displayFormat, decimals); } } else if ((qnFormat & QnfEnum.StdErr) != 0) // standard error { if (qn.StandardError != NullValue.NullNumber) { result = FormatNumber(qn.StandardError, displayFormat, decimals); } } else if ((qnFormat & QnfEnum.NValue) != 0) // N { if (qn.NValue != NullValue.NullNumber) { result = qn.NValue.ToString(); } } else if ((qnFormat & QnfEnum.NValueTested) != 0) // number tested { if (qn.NValueTested != NullValue.NullNumber) { result = qn.NValueTested.ToString(); } } else if ((qnFormat & QnfEnum.TextValue) != 0) // text value { if (!Lex.IsNullOrEmpty(qn.TextValue)) { result = qn.TextValue; } } return(result); }