using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.IO; using System.Drawing; using System.Windows.Forms; using System.Runtime.Serialization.Formatters.Binary; using System.Runtime.Serialization; using Microsoft.Win32; namespace trackDesigner { class trackDocument { // application specific data const int MAX_SIZE = 30; const int MAX_TRAINS = 5; // array of objects : turnouts, sensors, track links, trains private turnout[] myTurnouts; private int tCount; private sensor[] mySensors; private int sCount; private train[] myTrains; private int trCt; private trackStructure[] myTrack; private int num_segments; editForm eForm; private int shift_factor; // "any document" data private bool isModified = false; private string fileName = ""; private Form host; private string defaultFileName = "Untitled"; private string fileExtension = "ccr"; // "ccr" private string fileExtensionDesc = "battleship"; private bool registerFileExtension = false; private string filter = "CCR Files (*.ccr) |*.ccr"; private string iconResourceIndex = "ccrIcon2.ico"; /********* CONSTRUCTOR *************/ public trackDocument() { mySensors = new sensor[3*MAX_SIZE]; sCount = 0; myTrains = new train[MAX_TRAINS]; trCt = 0; myTurnouts = new turnout[MAX_SIZE]; tCount = 0; myTrack = new trackStructure[MAX_SIZE]; num_segments = 0; eForm = new editForm(); shift_factor = 0; } /********* PROPERTIES *************/ /* PROPERTIES - generic document */ public bool RegisterFileExtensionWithShell /* SELLS/MCVEY */ { get { return this.registerFileExtension; } set { this.registerFileExtension = value; } } public Form Host { set { host = value; } get { return host; } } public bool HasBeenModified { set { isModified = value; } get { return isModified; } } public string FileName { set { fileName = value; } get { return fileName; } } /* PROPERTIES - specific application */ /* ONLY ALLOW ACCESS - NO CHANGING */ public int sh_fac { get { return shift_factor; } } public trackStructure[] track { get { return myTrack; } } public int segs { get { return num_segments; } } public turnout[] turnout { get { return myTurnouts; } } public int turnCt { get { return tCount; } } public sensor[] sensor { get { return mySensors; } } public int sensorCt { get { return sCount; } } public train[] train { get { return myTrains; } } public int trainCt { get { return trCt; } set { trCt = value; } } /* EVENTS */ public event EventHandler NewDocument; public event EventHandler OpenDocument; public event EventHandler UpdateCaption; /************** METHODS ***************/ /******************************************************************* Method Name: EditTrack Purpose: opens editForm that allows users to create/modify a track. * Fills data structures with appropriate information if editForm * returns successfully. Calculates shift_factor needed for * trackDesigner form Input: None Output: boolean variable stating whether the edit returned * successfully *******************************************************************/ public bool EditTrack() { eForm = new editForm(); eForm.a_mode = true; eForm.track = myTrack; eForm.segs = num_segments; if (eForm.ShowDialog() == DialogResult.OK) { myTrack = eForm.track; num_segments = eForm.segs; tCount = 0; sCount = 0; int diff = -1000; int big_diff = -1000; // calculate shift_factor for (int i = 0; i < num_segments; i++) { if (myTrack[i].ptA.loc.Y < 75) { diff = 75 - myTrack[i].ptA.loc.Y; if (diff > big_diff) big_diff = diff; } if (myTrack[i].ptMid.loc.Y < 75) { diff = 75 - myTrack[i].ptMid.loc.Y; if (diff > big_diff) big_diff = diff; } if (myTrack[i].ptB.loc.Y < 75) { diff = 75 - myTrack[i].ptB.loc.Y; if (diff > big_diff) big_diff = diff; } } if (big_diff != -1000) shift_factor = big_diff; // fill the data structures with everything HERE for (int i = 0; i < num_segments; i++) { if (myTrack[i].ptA.num_connected > 2) { // add it to the turnouts only if it hasn't already been added // then "mark" it myTrack[i].ptA.num_connected = -10; myTurnouts[tCount] = new turnout(myTrack[i].ptA.loc, 'S'); tCount++; } else if (myTrack[i].ptA.num_connected > 0) { // add it to the sensors & "mark" it myTrack[i].ptA.num_connected *= -1; mySensors[sCount] = new sensor(myTrack[i].ptA.loc, false); sCount++; } mySensors[sCount] = new sensor(myTrack[i].ptMid.loc, false); sCount++; if (myTrack[i].ptB.num_connected > 2) { // add it to the turnouts myTrack[i].ptB.num_connected = -10; myTurnouts[tCount] = new turnout(myTrack[i].ptB.loc, 'S'); tCount++; } else if (myTrack[i].ptB.num_connected > 0) { // add it to the sensors myTrack[i].ptB.num_connected *= -1; mySensors[sCount] = new sensor(myTrack[i].ptB.loc, false); sCount++; } } for (int i = 0; i < num_segments; i++) { // return to "turnout" or "sensor" status if (myTrack[i].ptA.num_connected == -10) myTrack[i].ptA.num_connected = 3; else if (myTrack[i].ptA.num_connected < 0) myTrack[i].ptA.num_connected *= -1; if (myTrack[i].ptB.num_connected == -10) myTrack[i].ptB.num_connected = 3; else if (myTrack[i].ptB.num_connected < 0) myTrack[i].ptB.num_connected *= -1; } return true; } else return false; } /************************************************************************ * SAVE, OPEN and NEW tasks are ALL adapted from the * * SELLS/MCVEY example we did in lab in CSCI 350!!!! * * * * CHANGES ARE MARKED * * * * * * **********************************************************************/ /*** New document ***/ public bool NewFile(bool fromCGSum) // CHANGE to prototype... bool for whether or not { // this came from a button click in interface DialogResult res = DialogResult.No; if (!fromCGSum) // only ask to save if it did NOT come from button { if (isModified) { res = MessageBox.Show("Would you like to save changes?", fileName, MessageBoxButtons.YesNoCancel); } } if (res != DialogResult.Cancel) { if (res == DialogResult.Yes) { Save(); } isModified = false; fileName = defaultFileName; /***** MY STUFF *****/ num_segments = 0; trCt = 0; sCount = 0; tCount = 0; /******* END MY STUFF ********/ // Let subscribers know a "new" document has been "created" if (this.NewDocument != null) this.NewDocument(this, EventArgs.Empty); if (this.UpdateCaption != null) this.UpdateCaption(this, EventArgs.Empty); } return true; } /*** Open existing file ***/ public bool Open() { return Open(null); } public bool Open(string newFileName) { DialogResult res1 = DialogResult.No; if (isModified) { res1 = MessageBox.Show("Would you like to save changes?", fileName, MessageBoxButtons.YesNoCancel); } if (res1 != DialogResult.Cancel) { if (res1 == DialogResult.Yes) { Save(); } // Get a file name OpenFileDialog dlg = new System.Windows.Forms.OpenFileDialog(); if (string.IsNullOrEmpty(newFileName)) { // Set up dialog dlg.DefaultExt = fileExtension; dlg.Filter = filter; // Get the file to open DialogResult res = dlg.ShowDialog(this.host); if (res != DialogResult.OK) return false; newFileName = dlg.FileName; } // Read the data /******** MY STUFF *********/ // create new forms for status of trains and sensors/turnouts<--ONLY NEED THIS IF YOU ALLOW // THE USER TO SAVE THE PROGRAM WHILE THE SIMULATOR IS RUNNING. I DO NOT ALLOW AS OF NOW. try { using (StreamReader sr = new StreamReader(newFileName)) { string x = sr.ReadLine(); shift_factor = Convert.ToInt32(x); x = sr.ReadLine(); num_segments = Convert.ToInt32(x); for (int i = 0; i < num_segments; i++) { // one line per trackPt so three lines per seg myTrack[i] = new trackStructure(); x = sr.ReadLine(); string[] a = x.Split(';'); myTrack[i].ptA = new trackPt(new Point(Convert.ToInt32(a[0]), Convert.ToInt32(a[1])), Convert.ToInt32(a[2]), false, Convert.ToInt32(a[3]), Convert.ToInt32(a[4])); x = sr.ReadLine(); a = x.Split(';'); myTrack[i].ptMid = new trackPt(new Point(Convert.ToInt32(a[0]), Convert.ToInt32(a[1])), Convert.ToInt32(a[2]), true, Convert.ToInt32(a[3]), Convert.ToInt32(a[4])); x = sr.ReadLine(); a = x.Split(';'); myTrack[i].ptB = new trackPt(new Point(Convert.ToInt32(a[0]), Convert.ToInt32(a[1])), Convert.ToInt32(a[2]), false, Convert.ToInt32(a[3]), Convert.ToInt32(a[4])); } x = sr.ReadLine(); sCount = Convert.ToInt32(x); for (int i = 0; i < sCount; i++) { x = sr.ReadLine(); string[] a = x.Split(';'); mySensors[i] = new sensor(new Point(Convert.ToInt32(a[0]), Convert.ToInt32(a[1])), Convert.ToBoolean(a[2])); } x = sr.ReadLine(); tCount = Convert.ToInt32(x); for (int i = 0; i < tCount; i++) { x = sr.ReadLine(); string[] a = x.Split(';'); myTurnouts[i] = new turnout(new Point(Convert.ToInt32(a[0]), Convert.ToInt32(a[1])), Convert.ToChar(a[2])); } x = sr.ReadLine(); trCt = Convert.ToInt32(x); for (int i = 0; i < trCt; i++) { myTrains[i] = new train(); for (int j = 0; j < 4; j++) { x = sr.ReadLine(); string[] a = x.Split(';'); myTrains[i].loc[j] = new Point(Convert.ToInt32(a[0]), Convert.ToInt32(a[1])); } x = sr.ReadLine(); string[] a1 = x.Split(';'); myTrains[i].direction = Convert.ToInt32(a1[0]); myTrains[i].speed = Convert.ToInt32(a1[1]); myTrains[i].ctr = Convert.ToInt32(a1[2]); myTrains[i].firstcar = Convert.ToInt32(a1[3]); myTrains[i].color = a1[4]; myTrains[i].state = Convert.ToChar(a1[5]); } } /********** END MY STUFF ***********/ } catch (Exception e) { MessageBox.Show(host, "Can't open file: " + newFileName + "\r\n" + e.Message, Application.ProductName); return false; } // Clear dirty bit, cache the file name and set the caption this.isModified = false; this.fileName = newFileName; /********* MY STUFF ***********/ // this is where I bring up status forms for each train/sensors/turnouts /********** END MY STUFF *********/ // Success if (this.OpenDocument != null) this.OpenDocument(this, EventArgs.Empty); if (this.UpdateCaption != null) this.UpdateCaption(this, EventArgs.Empty); } return true; } /*** Saving the data ***/ public bool Save() { return Save(false); } public bool SaveAs() { return Save(true); } protected bool Save(bool type) { // Get the file name string newFileName = fileName; // I added the || fileName == "Untitled" to this if stmt if (type || string.IsNullOrEmpty(newFileName) || fileName == "Untitled") { // Set up the dialog SaveFileDialog dlg = new SaveFileDialog(); dlg.DefaultExt = fileExtension; dlg.Filter = filter; if (!string.IsNullOrEmpty(newFileName)) { dlg.InitialDirectory = Path.GetDirectoryName(newFileName); dlg.FileName = Path.GetFileName(newFileName); } else { dlg.FileName = this.fileName; } DialogResult res = dlg.ShowDialog(this.host); if (res != DialogResult.OK) return false; newFileName = dlg.FileName; } // Write the data try { using (StreamWriter sw = new StreamWriter(newFileName)) { /********* MY STUFF *********/ sw.WriteLine(shift_factor.ToString()); // write the graphical track sw.WriteLine(num_segments.ToString()); for (int i = 0; i < num_segments; i++) { // don't need to save the bool for midpt... already know when // it's read in bc the 2nd of the three is always the midpt sw.WriteLine(myTrack[i].ptA.loc.X.ToString()+';'+ myTrack[i].ptA.loc.Y.ToString()+';'+ myTrack[i].ptA.num_connected.ToString()+';'+ myTrack[i].ptA.val1.ToString()+';'+ myTrack[i].ptA.val2.ToString()); sw.WriteLine(myTrack[i].ptMid.loc.X.ToString()+';'+ myTrack[i].ptMid.loc.Y.ToString()+';'+ myTrack[i].ptMid.num_connected.ToString() + ';' + myTrack[i].ptMid.val1.ToString() + ';' + myTrack[i].ptMid.val2.ToString()); sw.WriteLine(myTrack[i].ptB.loc.X.ToString() + ';' + myTrack[i].ptB.loc.Y.ToString() + ';' + myTrack[i].ptB.num_connected.ToString() + ';' + myTrack[i].ptB.val1.ToString() + ';' + myTrack[i].ptB.val2.ToString()); } // write the sensors (this matters bc of their STATES) sw.WriteLine(sCount.ToString()); for (int i = 0; i < sCount; i++) { sw.WriteLine(mySensors[i].loc.X.ToString()+';'+ mySensors[i].loc.Y.ToString()+';'+ mySensors[i].covered.ToString()); } // write turnouts (matters bc of their STATES) sw.WriteLine(tCount.ToString()); for (int i = 0; i < tCount; i++) { sw.WriteLine(myTurnouts[i].loc.X.ToString() + ';' + myTurnouts[i].loc.Y.ToString() + ';' + myTurnouts[i].state); } // write trains bc location/direction/state can change sw.WriteLine(trCt.ToString()); for (int i = 0; i < trCt; i++) { for(int j=0; j<4; j++) { sw.WriteLine(myTrains[i].loc[j].X.ToString() + ';' + myTrains[i].loc[j].Y.ToString()); } sw.WriteLine(myTrains[i].direction.ToString()+';'+ myTrains[i].speed.ToString()+';'+ myTrains[i].ctr.ToString() + ';' + myTrains[i].firstcar.ToString()+';'+ myTrains[i].color+';'+ myTrains[i].state); } /********** END MY STUFF *********/ } } catch (Exception e) { MessageBox.Show(host, "Can't save file: " + newFileName + "\r\n" + e.Message, Application.ProductName); return false; } // Clear the dirty bit, cache the new file name and set the caption isModified = false; fileName = newFileName; if (this.UpdateCaption != null) this.UpdateCaption(this, EventArgs.Empty); return true; } /********************* SELLS/MCVEY ****************************/ public void CheckRegisterFileExtension() { if (!this.registerFileExtension || string.IsNullOrEmpty(this.fileExtension)) return; // Register custom extension with the shell string progID = this.fileExtension + "file"; using (RegistryKey key = Registry.ClassesRoot.CreateSubKey("." + this.fileExtension)) { // Map custom extension to a ProgID key.SetValue(null, progID); } // Set ProgID description if (!string.IsNullOrEmpty(this.fileExtensionDesc)) { using (RegistryKey key = Registry.ClassesRoot.CreateSubKey(progID)) { key.SetValue(null, this.fileExtensionDesc); } } // Register open command with the shell string cmdkey = progID + @"\shell\open\command"; using (RegistryKey key = Registry.ClassesRoot.CreateSubKey(cmdkey)) { // Map ProgID to an Open action for the shell key.SetValue(null, string.Format("\"{0}\" \"%L\"", Application.ExecutablePath)); } // Register document icon with the shell - doesn't seem to work if (string.IsNullOrEmpty(this.iconResourceIndex)) return; string icokey = progID + @"\DefaultIcon"; using (RegistryKey key = Registry.ClassesRoot.CreateSubKey(icokey)) { // Map ProgID to a document icon for the shell key.SetValue(null, Application.ExecutablePath + "," + this.iconResourceIndex); } } } }