/// <summary> /// Write the path to file. This will need to confirm to the MSTS definition for .pat files. /// </summary> /// <param name="trainpath">The path itself, that needs to be written</param> public static void WritePatFile(Trainpath trainpath) { if (trainpath == null) { return; } if (trainpath.IsBroken) { InformUserPathIsBroken(); //return; } if (trainpath.FirstNode == null) { DisplayNoPathAvailable(); return; } if (UserCancelledBecauseOfUnfinishedPath(trainpath)) { return; } if (GetFileName(trainpath)) { CreatePDPsAndTrpathNodes(trainpath); WriteToFile(trainpath); trainpath.IsModified = false; } }
static bool UserCancelledBecauseOfUnfinishedPath(Trainpath trainpath) { List <string> cancelReasons = new List <string>(); if (!trainpath.HasEnd) { cancelReasons.Add(TrackViewer.catalog.GetString("* The path does not have a well-defined end-point")); } //if (trainpath.IsBroken) cancelReasons.Add(TrackViewer.catalog.GetString("* The path has broken nodes or links")); if (trainpath.FirstNodeOfTail != null) { cancelReasons.Add(TrackViewer.catalog.GetString("* The path has a stored and not-yet reconnected tail")); } if (cancelReasons.Count == 0) { return(false); } string message = TrackViewer.catalog.GetString("The current path is not finished:") + "\n"; message += String.Join("\n", cancelReasons.ToArray()); message += "\n" + TrackViewer.catalog.GetString("Do you want to continue?"); DialogResult dialogResult = MessageBox.Show(message, TrackViewer.catalog.GetString("Trackviewer Path Editor"), MessageBoxButtons.OKCancel, MessageBoxIcon.Question); return(dialogResult == DialogResult.Cancel); }
/// <summary> /// Write the path to file. This will need to confirm to the MSTS definition for .pat files. /// The user will be prompted for the path and possibly other things just to make sure /// </summary> /// <param name="trainpath">The path itself, that needs to be written</param> public static void WritePatFile(Trainpath trainpath) { if (trainpath == null) { return; } if (trainpath.IsBroken) { InformUserPathIsBroken(); //return; } if (trainpath.FirstNode == null) { DisplayNoPathAvailable(); return; } if (UserCancelledBecauseOfUnfinishedPath(trainpath)) { return; } if (GetFileName(trainpath)) { WritePatFileDirect(trainpath); } }
/// <summary> /// Actual output routine. Here also path properties like Name, Start, and End are added. /// </summary> /// <param name="trainpath">The path, needed for some properties</param> /// <remarks>Output will be in unicode, and also in US-EN</remarks> private static void WriteToFile(Trainpath trainpath) { System.IO.StreamWriter file = new System.IO.StreamWriter(fullFilePath, false, System.Text.Encoding.Unicode); file.WriteLine("SIMISA@@@@@@@@@@JINX0P0t______"); file.WriteLine(""); file.WriteLine("Serial ( 1 )"); file.WriteLine("TrackPDPs ("); foreach (string line in trackPDPs) { file.WriteLine(line); } file.WriteLine(")"); file.WriteLine("TrackPath ("); file.WriteLine("\tTrPathName ( \"" + trainpath.PathId + "\" )"); // How to format hex? "{0:X8}" is not working for me. Neither is {0:X08}. // Fortunately, {0:X} will use 8 characters anyway. Maybe because it knows the length from the number of bits in the number string flagsString = string.Format(System.Globalization.CultureInfo.InvariantCulture, "{0:X}", trainpath.PathFlags); file.WriteLine("\tTrPathFlags ( " + flagsString + " )"); file.WriteLine("\tName ( \"" + trainpath.PathName + "\" )"); file.WriteLine("\tTrPathStart ( \"" + trainpath.PathStart + "\" )"); file.WriteLine("\tTrPathEnd ( \"" + trainpath.PathEnd + "\" )"); file.Write("\tTrPathNodes ( "); file.WriteLine(trpathnodes.Count()); foreach (string line in trpathnodes) { file.WriteLine(line); } file.WriteLine("\t)"); file.WriteLine(")"); file.Close(); }
/// <summary> /// Constructor. This will actually load the .pat from file and create menus as needed /// </summary> /// <param name="routeData">The route information that contains track data base and track section data</param> /// <param name="drawTrackDB">The drawn tracks to know about where the mouse is</param> /// <param name="path">Path to the .pat file</param> public PathEditor(RouteData routeData, DrawTrackDB drawTrackDB, ORTS.Menu.Path path) : this(routeData, drawTrackDB) { FileName = path.FilePath.Split('\\').Last(); CurrentTrainPath = new Trainpath(trackDB, tsectionDat, path.FilePath); EditingIsActive = false; OnPathChanged(); }
/// <summary> /// Constructor. This will create a new empty path. /// </summary> /// <param name="routeData">The route information that contains track data base and track section data</param> /// <param name="drawTrackDB">The drawn tracks to know about where the mouse is</param>/// <param name="pathsDirectory">The directory where paths will be stored</param> public PathEditor(RouteData routeData, DrawTrackDB drawTrackDB, string pathsDirectory) : this(routeData, drawTrackDB) { CurrentTrainPath = new Trainpath(trackDB, tsectionDat); FileName = CurrentTrainPath.PathId + ".pat"; CurrentTrainPath.FilePath = System.IO.Path.Combine(pathsDirectory, FileName); EditingIsActive = true; OnPathChanged(); }
/// <summary> /// Get the filename to save the path file from the user. /// </summary> /// <param name="trainpath">The current path to get the default file path and name</param> /// <returns>Boolean describing whether user wants to write to file or not.</returns> static bool GetFileName(Trainpath trainpath) { Microsoft.Win32.SaveFileDialog dlg = new Microsoft.Win32.SaveFileDialog(); dlg.OverwritePrompt = true; dlg.InitialDirectory = Path.GetDirectoryName(trainpath.FilePath); dlg.FileName = trainpath.PathId; dlg.DefaultExt = ".pat"; dlg.Filter = "PAT Files (.pat)|*.pat"; if (dlg.ShowDialog() == true) { fullFilePath = dlg.FileName; trainpath.FilePath = fullFilePath; return(true); } return(false); }
/// <summary> /// Get the filename to save the path file from the user. /// </summary> /// <param name="trainpath">The current path to get the default file path and name</param> /// <returns>Boolean describing whether user wants to write to file or not.</returns> private static bool GetFileName(Trainpath trainpath) { Microsoft.Win32.SaveFileDialog dlg = new Microsoft.Win32.SaveFileDialog { OverwritePrompt = true, InitialDirectory = Path.GetDirectoryName(trainpath.FilePath), FileName = trainpath.PathId, DefaultExt = ".pat", Filter = "PAT Files (.pat)|*.pat" }; if (dlg.ShowDialog() == true) { trainpath.FilePath = dlg.FileName; return(true); } return(false); }
/// <summary> /// Run through all path nodes and create the trackPDPs and the trPathNodes /// </summary> /// <param name="trainpath">The path itself, that needs to be written</param> static void CreatePDPsAndTrpathNodes(Trainpath trainpath) { trackPDPs = new List <string>(); trpathnodes = new List <string>(); pdpOfJunction = new Dictionary <int, int>(); uint nextMainIndex = 1; TrainpathNode currentMainNode = trainpath.FirstNode; while (currentMainNode.NextMainNode != null) { TrainpathNode nextMainNode = currentMainNode.NextMainNode; if (currentMainNode.NextSidingNode == null) { AddNode(currentMainNode, nextMainIndex, nonext); } else { // This is a siding start. // We print, in this else statement, the siding start, and all extra siding nodes. // But we also need to know, for the last siding node, the siding end index, which is on main track. uint nextSidingIndex = nextMainIndex; // Find the amount of extra nodes in the siding path. // This can be 0 or more. uint extraSidingNodes = 0; TrainpathNode currentSidingNode = currentMainNode.NextSidingNode; while (currentSidingNode.NextSidingNode != null) { extraSidingNodes++; currentSidingNode = currentSidingNode.NextSidingNode; } nextMainIndex += extraSidingNodes; // Find the number of main Nodes TrainpathNode sidingEndNode = currentSidingNode; TrainpathNode tempMainNode = currentMainNode.NextMainNode; uint extraMainNodes = 0; while (tempMainNode != sidingEndNode) { extraMainNodes++; tempMainNode = tempMainNode.NextMainNode; // It should exist, if not path editor itself is broken. } if (extraSidingNodes == 0) { // Apparently there are no extra nodes in the siding, it is a direct path AddNode(currentMainNode, nextMainIndex, nextMainIndex + extraMainNodes); } else { // Write the siding start node AddNode(currentMainNode, nextMainIndex, nextSidingIndex); // Write the intermediate siding nodes, so neither the first nor the last // For simple passing paths, there are no intermeidate siding nodes currentSidingNode = currentMainNode.NextSidingNode; while (currentSidingNode.NextSidingNode.NextSidingNode != null) { nextSidingIndex++; AddNode(currentSidingNode, nonext, nextSidingIndex); currentSidingNode = currentSidingNode.NextSidingNode; } // Write the final siding node, linking to main path again. AddNode(currentSidingNode, nonext, nextMainIndex + extraMainNodes); } } nextMainIndex++; currentMainNode = nextMainNode; } // final node AddNode(currentMainNode, nonext, nonext); }
/// <summary> /// Write the path to file. This will need to confirm to the MSTS definition for .pat files. /// No additional user checks on filename, etc. /// </summary> /// <param name="trainpath">The path itself, that needs to be written</param> public static void WritePatFileDirect(Trainpath trainpath) { CreatePDPsAndTrpathNodes(trainpath); WriteToFile(trainpath); trainpath.IsModified = false; }
/// <summary> /// Take a new path indicating a .pat file, load that path and make it into a tail. /// Then try to reconnect the tail. This will then extend the current path with the loaded path /// </summary> /// <param name="path">The path that needs to be loaded to act as an extension</param> public void ExtendWithPath(ORTS.Menu.Path path) { //If everything works as expected, up to three steps are taken that can all be 'Undo'ne: // * Remove End // * Add tail // * Reconnect tail FileName = path.FilePath.Split('\\').Last(); Trainpath newPath = new Trainpath(trackDB, tsectionDat, path.FilePath); // We have a current path and a new path. // First check if the new path is usable TrainpathNode newStart = newPath.FirstNode; if (newPath.FirstNode == null || newPath.FirstNode.NextMainNode == null) { MessageBox.Show(TrackViewer.catalog.GetString("The selected path contains no or only 1 node. The current path was not extended.")); return; } TrainpathNode lastNode = CurrentTrainPath.FirstNode; while (lastNode.NextMainNode != null) { lastNode = lastNode.NextMainNode; } if (CurrentTrainPath.HasEnd) { //We need to remove the end and remember the node for reconnection. //If the end node and the firstnode of the new path are very close together we must make //sure that the junctionnode that will added to replace the end node is not past the firstnode. TrainpathNode endNode = lastNode; lastNode = endNode.PrevNode; EditorActionRemoveEnd actionRemove = new EditorActionRemoveEnd(); bool endCanBeRemoved = actionRemove.MenuState(CurrentTrainPath, endNode, null, UpdateAfterEdits, 0, 0); if (endCanBeRemoved) { //This should always be possible, but we should call MenuState anyway because of some initialization it might be doing actionRemove.DoAction(); CurrentTrainPath.HasEnd = false; } } //Add the tail // The new path contains a startNode that we no longer need, so the tail connects to the next node CurrentTrainPath.StoreCurrentPath(); CurrentTrainPath.FirstNodeOfTail = newPath.FirstNode.NextMainNode; CurrentTrainPath.TailHasEnd = newPath.HasEnd; //Now we try to reconnect the tail automatically EditorActionAutoConnectTail action = new EditorActionAutoConnectTail(); bool actionCanBeExecuted = action.MenuState(CurrentTrainPath, lastNode, null, UpdateAfterEdits, 0, 0); if (actionCanBeExecuted) { action.DoAction(); MessageBox.Show(TrackViewer.catalog.GetString("The selected path has been added as tail and then reconnected.")); } else { MessageBox.Show(TrackViewer.catalog.GetString("The selected path has been added as tail. It was not possible to reconnect automatically.")); } //Make sure all of the path is drawn, so that also the tail is visible ExtendPathFull(); }