/// <summary> /// Gets the text to display in the given column for the provided entry. /// </summary> /// <param name="entry"></param> /// <param name="column"></param> /// <param name="blockingEntry"></param> /// <exception cref="NotImplementedException"></exception> /// <returns></returns> private static string GetColumnTextForItem(PlanEntry entry, PlanColumn column, string blockingEntry) { const int MaxNotesLength = 60; switch (column) { case PlanColumn.SkillName: return entry.ToString(); case PlanColumn.PlanGroup: return entry.PlanGroupsDescription; case PlanColumn.TrainingTime: return entry.TrainingTime.ToDescriptiveText(DescriptiveTextOptions.IncludeCommas); case PlanColumn.TrainingTimeNatural: return entry.NaturalTrainingTime.ToDescriptiveText(DescriptiveTextOptions.IncludeCommas); case PlanColumn.EarliestStart: return $"{entry.StartTime:ddd} {entry.StartTime:G}"; case PlanColumn.EarliestEnd: return $"{entry.EndTime:ddd} {entry.EndTime:G}"; case PlanColumn.PercentComplete: return $"{Math.Floor(entry.FractionCompleted * 100)}%"; case PlanColumn.SkillRank: return entry.Skill.Rank.ToString(CultureConstants.DefaultCulture); case PlanColumn.PrimaryAttribute: return entry.Skill.PrimaryAttribute.ToString(); case PlanColumn.SecondaryAttribute: return entry.Skill.SecondaryAttribute.ToString(); case PlanColumn.SkillGroup: return entry.Skill.Group.Name; case PlanColumn.PlanType: return entry.Type.ToString(); case PlanColumn.SPTotal: return entry.EstimatedTotalSkillPoints.ToNumericString(0); case PlanColumn.SPPerHour: return entry.SpPerHour.ToString(CultureConstants.DefaultCulture); case PlanColumn.Priority: return entry.Priority.ToString(CultureConstants.DefaultCulture); case PlanColumn.Conflicts: return blockingEntry; case PlanColumn.Notes: { if (String.IsNullOrEmpty(entry.Notes)) return String.Empty; string result = Regex.Replace(entry.Notes, @"(\r|\n)+", " ", RegexOptions.None); if (result.Length <= MaxNotesLength) return result; return result.Substring(0, MaxNotesLength) + "..."; } case PlanColumn.Cost: { if (entry.Level != 1 || entry.CharacterSkill.IsKnown) return String.Empty; return entry.CharacterSkill.IsOwned ? "Owned" : entry.Skill.FormattedCost; } case PlanColumn.SkillPointsRequired: return entry.SkillPointsRequired.ToNumericString(0); default: throw new NotImplementedException(); } }
/// <summary> /// Applies formatting to a ListViewItem if the entry is queued. /// </summary> /// <param name="lvi">ListViewItem to be formatted.</param> /// <param name="entry">Entry used to identify is queued.</param> private void HighlightQueuedSkills(ListViewItem lvi, PlanEntry entry) { if (!Settings.UI.PlanWindow.HighlightQueuedSkills) return; CCPCharacter ccpCharacter = m_character as CCPCharacter; // Current character isn't a CCP character, so can't have a Queue if (ccpCharacter == null) return; if (ccpCharacter.SkillQueue.Any(skillLevel => skillLevel.ToString() == entry.ToString())) lvi.ForeColor = Color.RoyalBlue; }
/// <summary> /// Formats the entry. /// </summary> /// <param name="entry">The entry.</param> /// <param name="lvi">The lvi.</param> private void FormatEntry(PlanEntry entry, ListViewItem lvi) { // Is it a prerequisite or a top level entry ? if (!Settings.UI.SafeForWork) { lvi.Font = Settings.UI.PlanWindow.HighlightPlannedSkills && entry.Type == PlanEntryType.Planned ? m_plannedSkillFont : m_prerequisiteSkillFont; } // Gray out entries that cannot be trained immediately if (!entry.CanTrainNow && Settings.UI.PlanWindow.DimUntrainable) lvi.ForeColor = m_nonImmedTrainablePlanEntryColor; // Checks if this entry has not prereq-met if (!entry.CharacterSkill.IsKnown) lvi.ForeColor = Color.Red; // Checks if this entry is a non-public skill if (!entry.CharacterSkill.IsPublic) lvi.ForeColor = Color.DarkRed; // Checks if this entry is not known but has prereq-met if (!entry.CharacterSkill.IsKnown && entry.CharacterSkill.IsPublic && entry.CharacterSkill.ArePrerequisitesMet) lvi.ForeColor = Color.LightSlateGray; // Checks if this entry is partially trained bool level = entry.Level == entry.CharacterSkill.Level + 1; if (Settings.UI.PlanWindow.HighlightPartialSkills) { bool partiallyTrained = entry.CharacterSkill.FractionCompleted > 0 && entry.CharacterSkill.FractionCompleted < 1; if (level && partiallyTrained) lvi.ForeColor = Color.Green; } HighlightQueuedSkills(lvi, entry); // Checks if this entry is currently training (even if it's paused) if (entry.CharacterSkill.IsTraining && level) { lvi.BackColor = Color.LightSteelBlue; lvi.ForeColor = Color.Black; } // Checks whether this entry will be blocked string blockingEntry = String.Empty; if (Settings.UI.PlanWindow.HighlightConflicts) { bool isAutoBlocking; bool isBlocked = Scheduler.SkillIsBlockedAt(entry.EndTime, out blockingEntry, out isAutoBlocking); bool showBlocked = true; CCPCharacter ccpCharacter = m_character as CCPCharacter; if (ccpCharacter != null) { PlanEntry planEntry = m_plan.GetEntry(entry.Skill, entry.Level); int indexOfEntry = m_plan.IndexOf(planEntry); QueuedSkill queueSkill = ccpCharacter.SkillQueue.ElementAtOrDefault(indexOfEntry); if (queueSkill != null) { showBlocked = (Plan.Name != EveMonConstants.CurrentSkillQueueText) || !isAutoBlocking || ((ccpCharacter.SkillQueue.Count == 1) && (indexOfEntry == 0) && (queueSkill.Skill == planEntry.Skill.ToCharacter(m_character))); } } if (isBlocked && showBlocked) { lvi.ForeColor = Color.Red; lvi.BackColor = Color.LightGray; } } // Update every column lvi.UseItemStyleForSubItems = m_pluggable == null; for (int columnIndex = 0; columnIndex < lvSkills.Columns.Count; columnIndex++) { // Regular columns (not pluggable-dependent) if (lvSkills.Columns[columnIndex].Tag != null) { PlanColumnSettings columnSettings = (PlanColumnSettings)lvSkills.Columns[columnIndex].Tag; lvi.SubItems[columnIndex].BackColor = lvi.BackColor; lvi.SubItems[columnIndex].ForeColor = lvi.ForeColor; lvi.SubItems[columnIndex].Text = GetColumnTextForItem(entry, columnSettings.Column, blockingEntry); } // Training time differences else { TimeSpan timeDifference; string result = String.Empty; if (entry.OldTrainingTime < entry.TrainingTime) { result = "+"; timeDifference = entry.TrainingTime - entry.OldTrainingTime; lvi.SubItems[columnIndex].BackColor = lvi.BackColor; lvi.SubItems[columnIndex].ForeColor = Color.DarkRed; } else if (entry.OldTrainingTime > entry.TrainingTime) { result = "-"; timeDifference = entry.OldTrainingTime - entry.TrainingTime; lvi.SubItems[columnIndex].BackColor = lvi.BackColor; lvi.SubItems[columnIndex].ForeColor = Color.DarkGreen; } else { timeDifference = TimeSpan.Zero; lvi.SubItems[columnIndex].BackColor = lvi.BackColor; lvi.SubItems[columnIndex].ForeColor = lvi.ForeColor; } result += timeDifference.ToDescriptiveText(DescriptiveTextOptions.IncludeCommas); lvi.SubItems[columnIndex].Text = result; } } }
/// <summary> /// Creates a plan entry and a list view item for it, from the given skill. /// </summary> /// <param name="skill"></param> /// <returns></returns> private ListViewItem CreatePlanItemForSkill(Skill skill) { // Gets the planned level of the skill. Int64 newLevel = m_plan.GetPlannedLevel(skill) + 1; if (skill.Level >= newLevel) newLevel = skill.Level + 1; // Quits if already on lv5 if (newLevel > 5) return null; // Creates the plan entry and list item for this level PlanEntry newEntry = new PlanEntry(m_plan, skill, newLevel); ListViewItem newItem = new ListViewItem(newEntry.ToString()) { Tag = newEntry }; return newItem; }
/// <summary> /// Adds the training time. /// </summary> /// <param name="settings">The settings.</param> /// <param name="shoppingListCandidate">if set to <c>true</c> [shopping list candidate].</param> /// <param name="entry">The entry.</param> /// <param name="builder">The builder.</param> private static void AddTrainingTime(PlanExportSettings settings, bool shoppingListCandidate, PlanEntry entry, StringBuilder builder) { if (!settings.EntryTrainingTimes && !settings.EntryStartDate && !settings.EntryFinishDate && (!settings.EntryCost || !shoppingListCandidate)) { return; } const DescriptiveTextOptions TimeFormat = DescriptiveTextOptions.FullText | DescriptiveTextOptions.IncludeCommas | DescriptiveTextOptions.SpaceText; builder.Append(" ("); bool needComma = false; // Training time if (settings.EntryTrainingTimes) { needComma = true; builder.Append(entry.TrainingTime.ToDescriptiveText(TimeFormat)); } // Training start date if (settings.EntryStartDate) { if (needComma) { builder.Append("; "); } needComma = true; builder.Append($"Start: {entry.StartTime.ToUniversalTime().DateTimeToTimeString()} UTC"); } // Training end date if (settings.EntryFinishDate) { if (needComma) { builder.Append("; "); } needComma = true; builder.Append($"Finish: {entry.EndTime.ToUniversalTime().DateTimeToTimeString()} UTC"); } // Skill cost if (settings.EntryCost && shoppingListCandidate) { if (needComma) { builder.Append("; "); } builder.Append(FormattableString.Invariant($"Cost: {entry.Skill.Cost:N0} ISK")); } builder.Append(')'); }
/// <summary> /// Prints a single entry /// </summary> /// <param name="g"></param> /// <param name="size"></param> /// <param name="index"></param> /// <param name="pe"></param> /// <returns></returns> private void PrintEntry(Graphics g, int index, PlanEntry pe) { SizeF size; // Print entry index if (m_settings.EntryNumber) { size = Print(g, index.ToString() + ": ", m_point); m_point.X += (int)size.Width; } // Print skill name and level size = PrintBold(g, pe.ToString(), m_point); m_point.X += (int)size.Width; // Print additional infos below if (m_settings.EntryTrainingTimes || m_settings.EntryStartDate || m_settings.EntryFinishDate) { // Jump to next line m_point.Y += (int)size.Height; m_point.X = 20; // Open parenthesis size = Print(g, " (", m_point); m_point.X += (int)size.Width; // Training time ? bool needComma = false; if (m_settings.EntryTrainingTimes) { size = Print(g, Skill.TimeSpanToDescriptiveText(pe.TrainingTime, DescriptiveTextOptions.FullText | DescriptiveTextOptions.IncludeCommas | DescriptiveTextOptions.SpaceText), m_point); m_point.X += (int)size.Width; needComma = true; } // Start date ? if (m_settings.EntryStartDate) { if (needComma) { size = Print(g, "; ", m_point); m_point.X += (int)size.Width; } size = Print(g, "Start: ", m_point); m_point.X += (int)size.Width; size = Print(g, pe.StartTime.ToString(), m_point); m_point.X += (int)size.Width; needComma = true; } // End date ? if (m_settings.EntryFinishDate) { if (needComma) { size = Print(g, "; ", m_point); m_point.X += (int)size.Width; } size = Print(g, "Finish: ", m_point); m_point.X += (int)size.Width; size = Print(g, pe.EndTime.ToString(), m_point); m_point.X += (int)size.Width; needComma = true; } // Close parenthesis size = Print(g, ")", m_point); m_point.X += (int)size.Width; } // Jump to next line m_point.X = 5; m_point.Y += (int)size.Height; }