Class for a single row in the character inventory grid.
		/// ------------------------------------------------------------------------------------
		/// <summary>
		/// Compares character inventory rows on the IsValid field.
		/// </summary>
		/// ------------------------------------------------------------------------------------
		private int InventoryIsValidComparer(CharacterInventoryRow x, CharacterInventoryRow y)
		{
			if (x == null && y == null)
				return 0;

			if (x == null)
				return -1;

			if (y == null)
				return 1;

			int retval = (s_inventorySortOrder == SortOrder.Ascending ?
				x.IsValid.CompareTo(y.IsValid) :
				y.IsValid.CompareTo(x.IsValid));
			// Use the character as a secondary sort field, since many if not most comparisons
			// will yield a 0 (same value), which could randomize a large number of items.
			if (retval == 0)
				return InventoryCharComparer(x, y);
			else
				return retval;
		}
		/// ------------------------------------------------------------------------------------
		/// <summary>
		/// Compares character inventory rows on the character field.
		/// </summary>
		/// ------------------------------------------------------------------------------------
		private int InventoryCharComparer(CharacterInventoryRow x, CharacterInventoryRow y)
		{
			if (x == null && y == null)
				return 0;

			if (x == null)
				return -1;

			if (y == null)
				return 1;

			if (m_inventoryCharComparer == null)
				m_inventoryCharComparer = new TsStringComparer(m_ws);

			return (s_inventorySortOrder == SortOrder.Ascending ?
				m_inventoryCharComparer.Compare(x.Character, y.Character) :
				m_inventoryCharComparer.Compare(y.Character, x.Character));
		}
		/// ------------------------------------------------------------------------------------
		/// <summary>
		/// Compares character inventory rows on the count field.
		/// </summary>
		/// ------------------------------------------------------------------------------------
		private static int InventoryCountComparer(CharacterInventoryRow x, CharacterInventoryRow y)
		{
			if (x == null && y == null)
				return 0;

			if (x == null)
				return -1;

			if (y == null)
				return 1;

			return (s_inventorySortOrder == SortOrder.Ascending ?
				x.Count.CompareTo(y.Count) :
				y.Count.CompareTo(x.Count));
		}
		/// ------------------------------------------------------------------------------------
		/// <summary>
		/// Fills the inventory grid.
		/// </summary>
		/// ------------------------------------------------------------------------------------
		private void FillInventoryGrid(List<TextTokenSubstring> tokenSubstrings)
		{
			using (new WaitCursor(this))
			{
				contextCtrl.ResetContextLists();
				m_characterCount = new Dictionary<string, int>();
				gridCharInventory.RowCount = 0;

				if (tokenSubstrings == null)
					return;

				var normalizedChars = new Dictionary<string, string>();
				var rows = new Dictionary<string, CharacterInventoryRow>();
				m_inventoryRows = new List<CharacterInventoryRow>();

				foreach (TextTokenSubstring txtTokSub in tokenSubstrings)
				{
					string chr;
					if (!normalizedChars.TryGetValue(txtTokSub.Text, out chr))
					{
						chr = m_chrPropEng.NormalizeD(txtTokSub.Text);
						if (chr == "\n" || chr == "\r" || !TsStringUtils.IsCharacterDefined(chr)
							|| !TsStringUtils.IsValidChar(chr, m_chrPropEng))
						{
							chr = string.Empty;
						}

						normalizedChars.Add(txtTokSub.Text, chr);
					}

					if (chr == string.Empty)
						continue;

					// Determine how many times this character has occurred previously and update
					// the counts for characters.
					int charCount;
					bool fAddOccurrence = true;
					if (m_characterCount.TryGetValue(chr, out charCount))
					{
						m_characterCount[chr]++;
						fAddOccurrence = (charCount < kMaxOccurrences);
					}
					else
						m_characterCount.Add(chr, 1); // First occurrence of this character

					// Only add the character occurrence to the list on the dialog if we have not
					// exceeded the threshold for this character.
					CharacterInventoryRow row;
					if (!rows.TryGetValue(chr, out row))
					{
						row = new CharacterInventoryRow(chr);
						rows[chr] = row;
						m_inventoryRows.Add(row);
						row.Count = m_characterCount[chr];
					}
					else
						row.Count = m_characterCount[chr];

					if (fAddOccurrence)
					{
						contextCtrl.AddContextInfo(new ContextInfo(chr, txtTokSub));
					}
				}

				int iSortedCol = SortedInventoryColumn;
				gridCharInventory.RowCount = m_inventoryRows.Count;
				gridCharInventory.Columns[iSortedCol].HeaderCell.SortGlyphDirection = s_inventorySortOrder;
				SortInventoryGrid();

				if (gridCharInventory.RowCount > 0)
					gridCharInventory.CurrentCell = gridCharInventory[0, 0];

				tabControlAddFrom_SelectedIndexChanged(null, null);
			}
		}