public AddDescriptionMode(Controller controller, UndoMgr undoMgr, SelectionMgr selectionMgr, EventDB eventDB, SymbolDB symbolDB, CourseDesignator courseDesignator, DescriptionLine[] description, DescriptionKind kind) { this.controller = controller; this.undoMgr = undoMgr; this.selectionMgr = selectionMgr; this.symbolDB = symbolDB; this.eventDB = eventDB; this.courseDesignator = courseDesignator; this.description = description; this.kind = kind; }
// Get the number of parts that this course has. A course with no map exchanges has 1 part, with one // map exchange has 2 parts, etc. public static int CountCourseParts(EventDB eventDB, CourseDesignator courseDesignator) { Debug.Assert(courseDesignator.AllParts); int currentPart = 0; foreach (Id<CourseControl> courseControlId in EnumCourseControlIds(eventDB, courseDesignator)) { if (eventDB.GetCourseControl(courseControlId).exchange) ++currentPart; } return currentPart + 1; }
// Check the validate of the selected course view/selected object and update accordingly. void UpdateSelection() { // Check the selection validity. if (!activeCourseDesignator.IsAllControls && !eventDB.IsCoursePresent(activeCourseDesignator.CourseId)) { // Active course was deleted. Switch to all controls. activeCourseDesignator = CourseDesignator.AllControls; ClearSelection(); } // Check that variation still exists. if (activeCourseDesignator.IsVariation && QueryEvent.HasVariations(eventDB, activeCourseDesignator.CourseId)) { IEnumerable<VariationInfo> variations = QueryEvent.GetAllVariations(eventDB, activeCourseDesignator.CourseId); if (!variations.Any(v => v.Equals(activeCourseDesignator.VariationInfo))) activeCourseDesignator = activeCourseDesignator.WithAllVariations(); } // Does the current part still exist? if (!activeCourseDesignator.IsAllControls && !activeCourseDesignator.AllParts && activeCourseDesignator.Part >= QueryEvent.CountCourseParts(eventDB, activeCourseDesignator.CourseId)) { // No part that large any more. int numberOfParts = QueryEvent.CountCourseParts(eventDB, activeCourseDesignator.CourseId); if (numberOfParts > 1) activeCourseDesignator = new CourseDesignator(activeCourseDesignator.CourseId, numberOfParts - 1); else activeCourseDesignator = new CourseDesignator(activeCourseDesignator.CourseId); ClearSelection(); } if (selectedCourseControl.IsNotNone && !eventDB.IsCourseControlPresent(selectedCourseControl)) { // Selected course control is no longer there. selectedCourseControl = Id<CourseControl>.None; ClearSelection(); } if (selectedCourseControl.IsNotNone && activeCourseDesignator.IsNotAllControls && (!activeCourseDesignator.AllParts || activeCourseDesignator.IsVariation) && !QueryEvent.IsCourseControlInPart(eventDB, activeCourseDesignator, selectedCourseControl)) { // Selected course control is not in active part. // Could be allowed if it's the finish. Id<ControlPoint> controlId = eventDB.GetCourseControl(selectedCourseControl).control; if (!(eventDB.IsControlPresent(controlId) && eventDB.GetControl(controlId).kind == ControlPointKind.Finish && QueryEvent.GetPartOptions(eventDB, activeCourseDesignator).ShowFinish)) { selectedCourseControl = Id<CourseControl>.None; ClearSelection(); } } if (selectedCourseControl2.IsNotNone && !eventDB.IsCourseControlPresent(selectedCourseControl2)) { // Selected course control 2 is no longer there. selectedCourseControl2 = Id<CourseControl>.None; ClearSelection(); } if (selectedCourseControl2.IsNotNone && activeCourseDesignator.IsNotAllControls && !activeCourseDesignator.AllParts && !QueryEvent.IsCourseControlInPart(eventDB, activeCourseDesignator, selectedCourseControl2)) { // Selected course control 2 is not in active part. selectedCourseControl2 = Id<CourseControl>.None; ClearSelection(); } if (selectedControl.IsNotNone && !eventDB.IsControlPresent(selectedControl)) { // Selected control is no longer there. ClearSelection(); } if (selectedSpecial.IsNotNone && !eventDB.IsSpecialPresent(selectedSpecial)) { // Selected special is no longer there. ClearSelection(); } if (selectedSpecial.IsNotNone && !(activeCourseDesignator.IsAllControls || QueryEvent.CourseContainsSpecial(eventDB, activeCourseDesignator, selectedSpecial))) { // Selected special is not in current course ClearSelection(); } }
// Create the normal view onto a score course private static CourseView CreateScoreCourseView(EventDB eventDB, CourseDesignator courseDesignator) { Course course = eventDB.GetCourse(courseDesignator.CourseId); CourseView courseView = new CourseView(eventDB, courseDesignator); Id<CourseControl> courseControlId; courseView.courseName = course.name; courseView.scoreColumn = course.scoreColumn; courseControlId = course.firstCourseControl; while (courseControlId.IsNotNone) { ControlView controlView = new ControlView(); CourseControl courseControl = eventDB.GetCourseControl(courseControlId); controlView.courseControlIds = new[] { courseControlId }; controlView.controlId = courseControl.control; // Ordinals assigned after sorting. controlView.ordinal = -1; controlView.joinIndex = -1; // Move to the next control. courseView.controlViews.Add(controlView); courseControlId = courseControl.nextCourseControl; } // Sort the control views: first by kind, then by score, then by code. courseView.controlViews.Sort(delegate(ControlView view1, ControlView view2) { ControlPoint control1 = eventDB.GetControl(view1.controlId); ControlPoint control2 = eventDB.GetControl(view2.controlId); CourseControl courseControl1 = eventDB.GetCourseControl(view1.courseControlIds[0]); CourseControl courseControl2 = eventDB.GetCourseControl(view2.courseControlIds[0]); if (control1.kind < control2.kind) return -1; else if (control1.kind > control2.kind) return 1; if (courseControl1.points != courseControl2.points) return courseControl1.points.CompareTo(courseControl2.points); int result = Util.CompareCodes(control1.code, control2.code); if (result != 0) return result; return view1.controlId.id.CompareTo(view2.controlId.id); }); // Assign ordinals, if applicable. If scores in column A, then no ordinals will be assigned. if (courseView.scoreColumn != 0) { int ordinal = course.firstControlOrdinal; foreach (ControlView control in courseView.controlViews) { if (eventDB.GetControl(control.controlId).kind == ControlPointKind.Normal) control.ordinal = ordinal++; } } courseView.Finish(); return courseView; }
// Create the view of all variations of a course with variations. Cannot be a single part of a multi-part course. // Does not contain ordinals. private static CourseView CreateAllVariationsCourseView(EventDB eventDB, CourseDesignator courseDesignator) { Course course = eventDB.GetCourse(courseDesignator.CourseId); if (!courseDesignator.AllParts) throw new ApplicationException("Cannot create all variations of a single part"); CourseView courseView = new CourseView(eventDB, courseDesignator); courseView.courseName = course.name; courseView.scoreColumn = -1; // To get the ordinals correct, we get the course control ids for all parts. List<Id<CourseControl>> courseControls = QueryEvent.EnumCourseControlIds(eventDB, courseDesignator).ToList(); for (int index = 0; index < courseControls.Count; ++index) { Id<CourseControl> courseControlId = courseControls[index]; CourseControl courseControl = eventDB.GetCourseControl(courseControlId); // We add each split control only once, even though it has multiple variations. Check to see if we have already // handled it. bool alreadyHandled = false; if (courseControl.split) { foreach (ControlView cv in courseView.controlViews) { if (cv.courseControlIds.Contains(courseControlId)) alreadyHandled = true; } } if (!alreadyHandled) { ControlView controlView = new ControlView(); controlView.controlId = courseControl.control; // Set the ordinal number. All variations does not include an ordinal. controlView.ordinal = -1; // Set all course control ids associated with split control, or a single one for a non-split control. // Set the legTo array with the next courseControlID(s). This is later updated // to the indices. if (courseControl.split) { controlView.courseControlIds = QueryEvent.AllVariationsOfCourseControl(eventDB, courseControlId).ToArray(); if (courseControl.nextCourseControl.IsNotNone) { controlView.legTo = new int[controlView.courseControlIds.Length]; for (int i = 0; i < controlView.legTo.Length; ++i) { controlView.legTo[i] = eventDB.GetCourseControl(controlView.courseControlIds[i]).nextCourseControl.id; } } if (courseControl.loop) controlView.joinIndex = courseControlId.id; else controlView.joinIndex = courseControl.splitEnd.id; } else { controlView.courseControlIds = new[] { courseControlId }; if (courseControl.nextCourseControl.IsNotNone) controlView.legTo = new int[1] { courseControl.nextCourseControl.id }; // legTo initially holds course control ids, later changed. controlView.joinIndex = -1; } // Add the controlview. courseView.controlViews.Add(controlView); } } courseView.Finish(); return courseView; }
// Create the course view for printing and OCAD export. If CourseId is 0, then the all controls view for printing. public static CourseView CreatePrintingCourseView(EventDB eventDB, CourseDesignator courseDesignator) { if (courseDesignator.IsAllControls) return CourseView.CreateFilteredAllControlsView(eventDB, null, ControlPointKind.None, true, true); else return CourseView.CreateCourseView(eventDB, courseDesignator, true, true); }
private float totalPoints; // total points. #endregion Fields #region Constructors private CourseView(EventDB eventDB, CourseDesignator courseDesignator) { this.eventDB = eventDB; this.courseDesignator = courseDesignator; }
// Add the appropriate specials for the given course to the course view. // If descriptionSpecialOnly is true, then only description sheet specials are added. private void AddSpecials(CourseDesignator courseDesignator, bool addNonDescriptionSpecials, bool addDescriptionSpecials) { bool multiPart = courseDesignator.IsNotAllControls && courseDesignator.AllParts && (QueryEvent.CountCourseParts(eventDB, courseDesignator.CourseId) > 1); foreach (Id<Special> specialId in eventDB.AllSpecialIds) { SpecialKind specialKind = eventDB.GetSpecial(specialId).kind; if (ShouldAddSpecial(specialKind, addNonDescriptionSpecials, addDescriptionSpecials)) { if (specialKind == SpecialKind.Descriptions) { // Descriptions are added differently. It's not entirely clear the best way to handle descriptions // for all-parts of a multi-part course. For now, we don't put any descriptions on. if (!multiPart) { if (QueryEvent.CourseContainsSpecial(eventDB, courseDesignator, specialId)) descriptionViews.Add(new DescriptionView(specialId, courseDesignator)); } } else { if (QueryEvent.CourseContainsSpecial(eventDB, courseDesignator, specialId)) specialIds.Add(specialId); } } } }
public static IEnumerable<LegInfo> EnumLegs(EventDB eventDB, CourseDesignator courseDesignator) { if (courseDesignator.IsAllControls) yield break; Id<Course> courseId = courseDesignator.CourseId; // Score courses, by definition, have no legs. if (eventDB.GetCourse(courseId).kind == CourseKind.Score) yield break; bool first = true; foreach (Id<CourseControl> courseControlId in EnumCourseControlIds(eventDB, courseDesignator)) { CourseControl courseControl = eventDB.GetCourseControl(courseControlId); if (first || courseDesignator.AllParts || !courseControl.exchange) { Id<CourseControl> nextCourseControlId = GetNextControl(eventDB, courseDesignator, courseControlId); if (nextCourseControlId.IsNotNone) { yield return new LegInfo(courseControlId, nextCourseControlId); } } first = false; } }
// Enumerate all the course controls ids for a particular course. public static IEnumerable<Id<CourseControl>> EnumCourseControlIds(EventDB eventDB, CourseDesignator courseDesignator) { Debug.Assert(courseDesignator.IsNotAllControls); Id<Course> courseId = courseDesignator.CourseId; int part = courseDesignator.Part; Id<CourseControl> firstCourseControlId = eventDB.GetCourse(courseId).firstCourseControl; int currentPart = 0; IEnumerable<Id<CourseControl>> variationChoices; if (! courseDesignator.IsVariation) variationChoices = null; else variationChoices = courseDesignator.VariationInfo.Path.Choices; return EnumCourseControlsToJoin(eventDB, courseDesignator, firstCourseControlId, Id<CourseControl>.None, variationChoices, false, currentPart); }
// Does courseControl1 precede courseControl2 in the given course. public static bool DoesCourseControlPrecede(EventDB eventDB, CourseDesignator courseDesignator, Id<CourseControl> courseControl1, Id<CourseControl> courseControl2) { bool sawFirst = false, sawSecond = false; foreach (Id<CourseControl> id in EnumCourseControlIds(eventDB, courseDesignator)) { if (id == courseControl1) sawFirst = true; else if (sawFirst && id == courseControl2) sawSecond = true; } return (sawFirst && sawSecond); }
// Get the full output file name. Uses the name of the course, removes bad characters, // checks for duplication of the map file name. // If courseDesignator is null, uses the event title insteand. public static string CreateOutputFileName(EventDB eventDB, CourseDesignator courseDesignator, string filePrefix, string fileSuffix, string extension) { string basename; // Get the course name. if (courseDesignator == null) basename = GetEventTitle(eventDB, " "); else if (courseDesignator.IsAllControls) basename = MiscText.AllControls; else basename = eventDB.GetCourse(courseDesignator.CourseId).name; // Add prefix, if requested. if (!string.IsNullOrEmpty(filePrefix)) basename = filePrefix + "-" + basename; // Add variation. if (courseDesignator != null && courseDesignator.IsVariation) { basename = basename + " " + courseDesignator.VariationInfo.Name; } // Add part. if (courseDesignator != null && !courseDesignator.AllParts) { basename = basename + "-" + (courseDesignator.Part + 1).ToString(); } if (!string.IsNullOrEmpty(fileSuffix)) basename = basename + fileSuffix; // Remove bad characters. basename = Util.FilterInvalidPathChars(basename); basename += extension; // add OCAD extension. return basename; }
// Return if a give course uses a given control. public static bool CourseUsesControl(EventDB eventDB, CourseDesignator courseDesignator, Id<ControlPoint> controlId) { eventDB.CheckControlId(controlId); foreach (Id<CourseControl> courseControlId in EnumCourseControlIds(eventDB, courseDesignator)) { if (eventDB.GetCourseControl(courseControlId).control == controlId) return true; } return false; }
public static bool CourseIsForked(EventDB eventDB, CourseDesignator courseDesignator) { foreach (Id<CourseControl> courseControlId in EnumCourseControlIds(eventDB, courseDesignator)) { if (eventDB.GetCourseControl(courseControlId).split) return true; } return false; }
// Does the given course (or all controls) contain the given special? public static bool CourseContainsSpecial(EventDB eventDB, CourseDesignator courseDesignator, Id<Special> specialId) { Special special = eventDB.GetSpecial(specialId); if (special.allCourses) return true; if (courseDesignator.AllParts) return special.courses.Any(cd => cd.CourseId == courseDesignator.CourseId); else return special.courses.Contains(courseDesignator) || special.courses.Contains(new CourseDesignator(courseDesignator.CourseId)); }
// Get the mapping from split course control to letter. public static Dictionary<Id<CourseControl>, char> GetVariantCodeMapping(EventDB eventDB, CourseDesignator courseDesignator) { Debug.Assert(!courseDesignator.IsVariation); char nextLetter = 'A'; Dictionary<Id<CourseControl>, char> result = new Dictionary<Id<CourseControl>, char>(); foreach (Id<CourseControl> courseControlId in EnumCourseControlIds(eventDB, courseDesignator)) { CourseControl courseControl = eventDB.GetCourseControl(courseControlId); if (courseControl.split) { foreach (Id<CourseControl> splitId in courseControl.splitCourseControls) { // The loop escape path doesn't get a letter. if (!(courseControl.loop && courseControl.splitCourseControls[0] == splitId)) { if (!result.ContainsKey(splitId)) { result.Add(splitId, nextLetter); if (nextLetter == 'Z') nextLetter = 'a'; else ++nextLetter; } } } } } return result; }
// Create the standard view onto a regular course, or a single variation of a variation course. private static CourseView CreateStandardCourseView(EventDB eventDB, CourseDesignator courseDesignator) { Course course = eventDB.GetCourse(courseDesignator.CourseId); if (QueryEvent.HasVariations(eventDB, courseDesignator.CourseId) && courseDesignator.VariationInfo == null) throw new ApplicationException("Cannot create course view without specifying which variation"); // Get sub-part of the course. firstCourseControls is the first control to process, lastCourseControl is the last one to // process, or None if process to the end of the course. Id<CourseControl> firstCourseControl, lastCourseControl; if (courseDesignator.AllParts) { firstCourseControl = course.firstCourseControl; lastCourseControl = Id<CourseControl>.None; } else { QueryEvent.GetCoursePartBounds(eventDB, courseDesignator, out firstCourseControl, out lastCourseControl); } CourseView courseView = new CourseView(eventDB, courseDesignator); int ordinal; courseView.courseName = course.name; courseView.scoreColumn = -1; ordinal = 1; ordinal = course.firstControlOrdinal; // To get the ordinals correct, we get the course control ids for all parts. List<Id<CourseControl>> courseControls = QueryEvent.EnumCourseControlIds(eventDB, courseDesignator.WithAllParts()).ToList(); int index = 0; // Increase the ordinal value for each normal control before the first one we're considering. while (index < courseControls.Count && courseControls[index] != firstCourseControl) { CourseControl courseControl = eventDB.GetCourseControl(courseControls[index]); ControlPoint control = eventDB.GetControl(courseControl.control); if (control.kind == ControlPointKind.Normal) ++ordinal; ++index; } for (; index < courseControls.Count; ++index) { Id<CourseControl> courseControlId = courseControls[index]; ControlView controlView = new ControlView(); CourseControl courseControl = eventDB.GetCourseControl(courseControlId); ControlPoint control = eventDB.GetControl(courseControl.control); controlView.courseControlIds = new[] { courseControlId }; controlView.controlId = courseControl.control; // Set the ordinal number. if (control.kind == ControlPointKind.Normal) controlView.ordinal = ordinal++; else if (control.kind == ControlPointKind.Start || control.kind == ControlPointKind.MapExchange) controlView.ordinal = 0; else controlView.ordinal = -1; controlView.joinIndex = -1; // Don't show the map exchange for the next part at the end of this part. if (courseControlId == lastCourseControl && !courseDesignator.AllParts && control.kind == ControlPointKind.MapExchange) { controlView.hiddenControl = true; } // Set the legTo array with the next courseControlID. This is later updated // to the indices. if (index < courseControls.Count - 1 && courseControlId != lastCourseControl) { Id<CourseControl> nextCourseControl = courseControls[index + 1]; controlView.legTo = new int[1] { nextCourseControl.id }; // legTo initially holds course control ids, later changed. } // Add the controlview. courseView.controlViews.Add(controlView); if (courseControlId == lastCourseControl) break; } // If this is a part that should also have the finish on it, and it isn't the last part, then // add the finish. if (courseDesignator.IsNotAllControls && !courseDesignator.AllParts && courseDesignator.Part != QueryEvent.CountCourseParts(eventDB, courseDesignator.CourseId) - 1 && QueryEvent.GetPartOptions(eventDB, courseDesignator).ShowFinish) { if (QueryEvent.HasFinishControl(eventDB, courseDesignator.CourseId)) courseView.extraCourseControls.Add(QueryEvent.LastCourseControl(eventDB, courseDesignator.CourseId, false)); } courseView.Finish(); return courseView; }
// Find the closest leg to a given point on a course. The leg might be None/None if the course has no legs. public static LegInfo FindClosestLeg(EventDB eventDB, CourseDesignator courseDesignator, PointF pt) { LegInfo closestLegSoFar = new LegInfo(); float closestSoFar = 1E10F; foreach (LegInfo leg in EnumLegs(eventDB, courseDesignator)) { PointF temp; SymPath legPath = GetLegPath(eventDB, eventDB.GetCourseControl(leg.courseControlId1).control, eventDB.GetCourseControl(leg.courseControlId2).control); float distance = legPath.DistanceFromPoint(pt, out temp); if (distance < closestSoFar) { closestSoFar = distance; closestLegSoFar = leg; } else if (distance == closestSoFar) { // Distances are equal. Use leg with the largest angle between the end points. SymPath closestLegPath = GetLegPath(eventDB, eventDB.GetCourseControl(closestLegSoFar.courseControlId1).control, eventDB.GetCourseControl(closestLegSoFar.courseControlId2).control); if (Geometry.Angle(legPath.FirstPoint, pt, legPath.LastPoint) > Geometry.Angle(closestLegPath.FirstPoint, pt, closestLegPath.LastPoint)) { closestSoFar = distance; closestLegSoFar = leg; } } } return closestLegSoFar; }
public DescriptionView(Id<Special> specialId, CourseDesignator courseDesignator) { this.SpecialId = specialId; this.CourseDesignator = courseDesignator; }
// Finds where a new regular control would be inserted into an existing course. courseControl1 and courseControl2 can either or both be none, to identify // a leg to insert into, a control to insert after, or no information about where to insert. Updates courseControl1 and courseControl2 to identify exactly // where on the course the control should be inserted as follows: // If inserting between two course controls -- these are denoted by courseControl1 and courseControl2 // If inserting as last course control -- courseControl1 is the current last control and courseControl2 is None (only occurs when there is no finish) // If inserting as first course control -- courseControl2 is None and courseControl2 is current first control (only occurs when there is no start) // If inserting as only course control -- both are none (only occurs if course is currently empty) public static void FindControlInsertionPoint(EventDB eventDB, CourseDesignator courseDesignator, ref Id<CourseControl> courseControl1, ref Id<CourseControl> courseControl2) { Id<Course> courseId = courseDesignator.CourseId; if (courseControl1.IsNotNone && courseControl2.IsNotNone) { CourseControl cc1 = eventDB.GetCourseControl(courseControl1); CourseControl cc2 = eventDB.GetCourseControl(courseControl2); if (cc1.nextCourseControl != courseControl2) { Debug.Assert(cc2.split && cc2.splitCourseControls.Contains(courseControl2)); courseControl2 = cc1.nextCourseControl; } return; } else { // Adding after courseControl1. If none, or a finish control, add at end, before the finish control if any. if (courseControl1.IsNone || eventDB.GetControl(eventDB.GetCourseControl(courseControl1).control).kind == ControlPointKind.Finish) courseControl1 = QueryEvent.LastCourseControl(eventDB, courseId, true); if (courseControl1.IsNone) { // Empty course or adding at start. courseControl2 = eventDB.GetCourse(courseId).firstCourseControl; return; } else { // Adding after courseControl1. CourseControl before = (CourseControl)eventDB.GetCourseControl(courseControl1); courseControl2 = before.nextCourseControl; return; } } }
// Create an filtered All Controls view -- show controls from the control collection, but only includes some. // excludedCourses contains an array of course ids to excluded from the contgrols. // kindFilter, if non-null, limits the controls to this kind of controls. public static CourseView CreateFilteredAllControlsView(EventDB eventDB, CourseDesignator[] excludedCourses, ControlPointKind kindFilter, bool addSpecials, bool addDescription) { CourseView courseView = new CourseView(eventDB, CourseDesignator.AllControls); courseView.courseName = MiscText.AllControls; courseView.scoreColumn = -1; // Add every control to the course view, subject to the filters. foreach (Id<ControlPoint> controlId in eventDB.AllControlPointIds) { ControlPoint control = eventDB.GetControl(controlId); // Check if the control is filtered out. if (excludedCourses != null) { // Filter excluded courses. foreach (CourseDesignator excludedCourseDesignator in excludedCourses) { if (QueryEvent.CourseUsesControl(eventDB, excludedCourseDesignator, controlId)) goto SKIP; } } if (kindFilter != ControlPointKind.None) { // Filter on control type. if (control.kind != kindFilter) goto SKIP; } // We are going to include this control in the collection. ControlView controlView = new ControlView(); controlView.courseControlIds = new[] { Id<CourseControl>.None }; controlView.controlId = controlId; // All controls doesn't have ordinals. controlView.ordinal = -1; controlView.joinIndex = -1; courseView.controlViews.Add(controlView); SKIP: ; } // Sort the control views: first by kind, then by code. courseView.controlViews.Sort((view1, view2) => QueryEvent.CompareControlIds(eventDB, view1.controlId, view2.controlId)); courseView.Finish(); if (addSpecials) { // Add every special, regardless of courses it is on, except for descriptions. Descriptions are added to all // controls only if they appear in all courses (or specifically for the all controls view), and if "addDescription" is true foreach (Id<Special> specialId in eventDB.AllSpecialIds) { Special special = eventDB.GetSpecial(specialId); if (special.kind == SpecialKind.Descriptions) { if (addDescription && QueryEvent.CourseContainsSpecial(eventDB, CourseDesignator.AllControls, specialId)) courseView.descriptionViews.Add(new DescriptionView(specialId, CourseDesignator.AllControls)); } else courseView.specialIds.Add(specialId); } } return courseView; }
// Get all the possible variations for a given course, based on the loops/forks. Returns a list of VariationInfo, // giving the code string, VariationPath, and name. Sorted by code string. public static IEnumerable<VariationInfo> GetAllVariations(EventDB eventDB, Id<Course> courseId) { HashSet<Id<CourseControl>> alreadyVisited = new HashSet<PurplePen.Id<PurplePen.CourseControl>>(); CourseDesignator courseDesignator = new CourseDesignator(courseId); Dictionary<Id<CourseControl>, char> variationMapper = GetVariantCodeMapping(eventDB, courseDesignator); List<List<Id<CourseControl>>> variations = GetVariations(eventDB, courseDesignator, eventDB.GetCourse(courseId).firstCourseControl, alreadyVisited); List<VariationInfo> result = new List<VariationInfo>(); // Check for no variations. if (variations.Count == 1 && variations[0].Count == 0) return result; foreach (var choices in variations) { string variationString = GetVariationString(eventDB, choices, variationMapper); VariationInfo.VariationPath variationPath = new VariationInfo.VariationPath(choices); result.Add(new VariationInfo(variationString, variationPath)); } result.Sort((vi1, vi2) => string.Compare(vi1.CodeString, vi2.CodeString, StringComparison.OrdinalIgnoreCase)); return result; }
// Create a course view for normal viewing. public static CourseView CreateViewingCourseView(EventDB eventDB, CourseDesignator courseDesignator) { if (courseDesignator.IsAllControls) return CourseView.CreateAllControlsView(eventDB); else return CourseView.CreateCourseView(eventDB, courseDesignator, true, true); }
// Find all the course controls for a particular control in a particular course. If the course // doesn't contain the given controlId, an empty array is returned. public static Id<CourseControl>[] GetCourseControlsInCourse(EventDB eventDB, CourseDesignator courseDesignator, Id<ControlPoint> controlId) { List<Id<CourseControl>> list = new List<Id<CourseControl>>(); foreach (Id<CourseControl> courseControlId in EnumCourseControlIds(eventDB, courseDesignator)) { if (eventDB.GetCourseControl(courseControlId).control == controlId) list.Add(courseControlId); } return list.ToArray(); }
// ----------- Static methods to create a new CourseView. ----------------- // Create a normal course view -- the standard view in order, from start control to finish control. courseId may NOT be None. private static CourseView CreateCourseView(EventDB eventDB, CourseDesignator courseDesignator, bool addNonDescriptionSpecials, bool addDescriptionSpecials) { Debug.Assert(! courseDesignator.IsAllControls); Course course = eventDB.GetCourse(courseDesignator.CourseId); CourseView courseView; if (course.kind == CourseKind.Score) courseView = CreateScoreCourseView(eventDB, courseDesignator); else if (course.kind == CourseKind.Normal) { if (QueryEvent.HasVariations(eventDB, courseDesignator.CourseId) && !courseDesignator.IsVariation) courseView = CreateAllVariationsCourseView(eventDB, courseDesignator); else courseView = CreateStandardCourseView(eventDB, courseDesignator); } else { Debug.Fail("Bad course kind"); return null; } courseView.AddSpecials(courseDesignator, addNonDescriptionSpecials, addDescriptionSpecials); return courseView; }
// Get the start and end coursecontrols (inclusive on both ends) for a particular part of a course (parts separated by map exchanges). // If the given part doesn't exist, return false. If there are no map exchanges, then part 0 is the entire course. public static bool GetCoursePartBounds(EventDB eventDB, CourseDesignator courseDesignator, out Id<CourseControl> startCourseControlId, out Id<CourseControl> endCourseControlId) { Debug.Assert(courseDesignator.IsNotAllControls); startCourseControlId = endCourseControlId = Id<CourseControl>.None; bool startFound = false; // did we find the beginning part of the course part? foreach (Id<CourseControl> courseControlId in EnumCourseControlIds(eventDB, courseDesignator)) { if (!startFound) { startFound = true; startCourseControlId = courseControlId; } endCourseControlId = courseControlId; } return startFound; }
// Select the course with the given id as the active tab, id==0 means all controls. public void SelectCourseView(CourseDesignator newDesignator) { UpdateState(); if (activeCourseDesignator != newDesignator) { bool courseChanged = (activeCourseDesignator.CourseId != newDesignator.CourseId); ++selectionChangeNum; activeCourseDesignator = newDesignator; // For now, when switching tabs (but not parts) the selection is cleared. // CONSIDER: maybe change this later; e.g., keep the selected control if it is in common. if (courseChanged) { ClearSelection(); } // CONSIDER: record a non-persistant command with the Undo Manager. } }
// Get the part options for a specific course part. Returns null for all controls. public static PartOptions GetPartOptions(EventDB eventDB, CourseDesignator courseDesignator) { if (courseDesignator.IsAllControls) return null; Course course = eventDB.GetCourse(courseDesignator.CourseId); PartOptions partOptions; if (!course.partOptions.TryGetValue(courseDesignator.Part, out partOptions)) { partOptions = PartOptions.Default; } // Show Finish is always true for the last part of the course. if (courseDesignator.Part == QueryEvent.CountCourseParts(eventDB, courseDesignator.CourseId) - 1) { partOptions = partOptions.Clone(); partOptions.ShowFinish = true; } return partOptions; }
CourseView topologyCourseView; // The active course view, but: null if all controls or score, plus always shows all variations and parts. #endregion Fields #region Constructors public SelectionMgr(EventDB eventDB, SymbolDB symbolDB, Controller controller) { this.eventDB = eventDB; this.symbolDB = symbolDB; this.controller = controller; this.activeCourseDesignator = CourseDesignator.AllControls; }
// Get the print area for a course, or for all controls if CourseId is none. public static PrintArea GetPrintArea(EventDB eventDB, CourseDesignator courseDesignator) { PrintArea printArea; if (courseDesignator.IsAllControls) printArea = eventDB.GetEvent().printArea; else { Course course = eventDB.GetCourse(courseDesignator.CourseId); printArea = course.printArea; if (!courseDesignator.AllParts && course.partPrintAreas.ContainsKey(courseDesignator.Part)) printArea = course.partPrintAreas[courseDesignator.Part]; } return printArea; }