/// ------------------------------------------------------------------------------------ /// <summary> /// Find the first and second interlinear fields in the RTF fields collection. /// </summary> /// ------------------------------------------------------------------------------------ private void GetFirstAndSecondInterlinearFields(out RTFFieldInfo firstField, out RTFFieldInfo secondField) { firstField = null; secondField = null; foreach (var rtfField in m_rtfFields) { //if (rtfField.isFirstLine) if (rtfField.isInterlinearField) { rtfField.isFirstLine = true; firstField = rtfField; int firstFieldIndex = m_rtfFields.IndexOf(firstField); // Find the second interlinear field for (int i = firstFieldIndex + 1; i < m_rtfFields.Count; i++) { if (m_rtfFields[i].isInterlinearField) { secondField = m_rtfFields[i]; break; } } return; } } }
/// ------------------------------------------------------------------------------------ /// <summary> /// Stores record's field names and their values in a collection. Only fields whose /// values are non null are saved. /// </summary> /// ------------------------------------------------------------------------------------ private void GetFieldsAndValuesFromRecord() { m_rtfFields.Clear(); m_numInterlinearFields = 0; m_firstILLineTabs = null; m_subordinateILLineTabs = null; using (Graphics g = CreateGraphics()) { // If there's more than one interlinear field, // then get the information for those fields. if (m_recEntry.HasInterlinearData || (m_recEntry.InterlinearFields != null && m_recEntry.InterlinearFields.Count > 1)) { GetInterlinearFieldsAndValues(g); } // Go through the fields in the record and use reflection to get their values // from the record cache entry. Don't bother with fields whose value is null, // those that aren't supposed to be visible in the record view, and those // that are interlinear (interlinear fields are handled above). foreach (var field in App.Project.Fields) { string fieldValue = m_recEntry[field.Name]; if (!field.VisibleInRecView || field.DisplayIndexInRecView < 0 || fieldValue == null || m_recEntry.GetIsInterlinearField(field.Name)) { continue; } // Save the field name, it's displayable name (e.g. Freeform = Free Form) // and the field's value. Replace any backslashes with double ones for // the sake of RTF. var info = new RTFFieldInfo(); info.field = field.Name; info.label = field.DisplayName; info.displayIndex = field.DisplayIndexInRecView; info.fieldValue = fieldValue.Replace("\\", "\\\\"); // All headers are bold using (var headerFont = FontHelper.MakeFont(FontHelper.UIFont, FontStyle.Bold)) { info.labelWidth = TextRenderer.MeasureText(g, field.DisplayName, headerFont, Size.Empty, kTxtFmtFlags).Width; } info.valueWidth = TextRenderer.MeasureText(g, fieldValue, field.Font, Size.Empty, kTxtFmtFlags).Width; m_rtfFields.Add(info); } } // Now sort the list on the order in which the fields should be displayed. m_rtfFields.Sort((x, y) => x.displayIndex.CompareTo(y.displayIndex)); }
/// ------------------------------------------------------------------------------------ private void FormatInterlinearForRTF(RTFFieldInfo rtfField, StringBuilder bldr, string firstLineTabStopsString, string subordinateTabStopsString) { bldr.AppendLine((rtfField.isFirstLine ? firstLineTabStopsString : subordinateTabStopsString)); int dataFontNumber = m_fontNumbers[rtfField.field]; int dataFontSize = m_fontSizes[rtfField.field]; Font dataFont = m_fonts[rtfField.field]; bldr.AppendFormat(kFmtOneLineOneCol, new object[] { m_fieldLabelColorRefNumber, m_uiFontSize, m_uiFontNumber, rtfField.label }); bldr.AppendFormat(kline, dataFontNumber, dataFontSize, string.Empty); for (int col = 0; col < rtfField.columnValues.Length; col++) { // The first field dosen't have sub columns. if (rtfField.isFirstLine) { bldr.Append(ApplyFontStyle(dataFont, true)); bldr.Append(rtfField.columnValues[col]); bldr.Append(ApplyFontStyle(dataFont, false)); bldr.Append("\\tab "); } else { // Go through the column's sub columns foreach (string subcolValue in rtfField.parsedColValues[col]) { bldr.Append(ApplyFontStyle(dataFont, true)); bldr.Append(subcolValue); bldr.Append(ApplyFontStyle(dataFont, false)); bldr.Append("\\tab "); } } } // Strip off the last tab and append the correct line ending marker. bldr.Remove(bldr.Length - 5, 5); if (m_useExactLineSpacing) { // Add a zero width space at the end of the line using the largest font so all // the lines will have uniform spacing between. I tried using a regular space // but the RTF control ignored it. I also tried forcing the line spacing using // the \slN RTF code, but that didn't seem to work either. It looked great in // Word, but not the RichTextBox. Grrr! bldr.AppendFormat(@"\fs{0}\f{1} {2}", m_maxFontSize, m_maxFontNumber, kZeroWidthSpace); } bldr.AppendLine(@"\par"); }
/// ------------------------------------------------------------------------------------ /// <summary> /// Gets the interlinear fields information. /// </summary> /// ------------------------------------------------------------------------------------ private void GetInterlinearFieldsAndValues(IDeviceContext g) { if (string.IsNullOrEmpty(m_recEntry.FirstInterlinearField)) { return; } SortedList sortedFieldInfo = new SortedList(); var tmpFields = new List <RTFFieldInfo>(); foreach (var fieldName in m_recEntry.InterlinearFields) { var field = App.Project.GetFieldForName(fieldName); string[] colValues = m_recEntry.GetParsedFieldValues(field, true); if (field == null || !field.VisibleInRecView || field.DisplayIndexInRecView < 0 || colValues == null) { continue; } var info = new RTFFieldInfo(); info.isInterlinearField = true; info.field = field.Name; info.label = field.DisplayName; info.displayIndex = field.DisplayIndexInRecView; info.columnValues = colValues; using (var headerFont = FontHelper.MakeFont(FontHelper.UIFont, FontStyle.Bold)) { info.labelWidth = TextRenderer.MeasureText(g, info.label, headerFont, Size.Empty, kTxtFmtFlags).Width; } // Sort the info by their display order sortedFieldInfo.Add(info.displayIndex, info); } bool firstField = true; foreach (RTFFieldInfo info in sortedFieldInfo.Values) { if (firstField) { // The first field is the one with the lowest DisplayIndexInRecView firstField = false; info.isFirstLine = true; tmpFields.Insert(0, info); } else { info.parsedColValues = new Dictionary <int, string[]>(); tmpFields.Add(info); } } // Now parse the columns into sub columns for interlinear // rows that are not the first interlinear row. if (tmpFields.Count > 1) // Make sure there are interlinear rows to parse { for (int col = 0; col < tmpFields[0].columnValues.Length; col++) { // Copy the values for each row for a single column. List <string> colValues = new List <string>(); for (int row = 1; row < tmpFields.Count; row++) { // If the current row doesn't have an value for // the current column just add an empty space. colValues.Add(col >= tmpFields[row].columnValues.Length ? string.Empty : tmpFields[row].columnValues[col]); } Dictionary <int, List <string> > parsedColValues = GetInterlinearSubColumnContents(colValues); // After parsing a single column, we need to save the results. for (int row = 1; row < tmpFields.Count; row++) { tmpFields[row].parsedColValues[col] = parsedColValues[row - 1].ToArray(); } } } m_numInterlinearFields = tmpFields.Count; m_rtfFields.AddRange(tmpFields); }