/// <summary> /// If name is null or invalid, throws an InvalidNameException. /// /// Otherwise, returns the value (as opposed to the contents) of the named cell. The return /// value should be either a string, a double, or a SpreadsheetUtilities.FormulaError. /// </summary> public override object GetCellValue(string name) { //if the name is valid gets the cell and returns its value isValidName(name); if (dictionary.ContainsKey(name)) { cell cell = new cell(); dictionary.TryGetValue(name, out cell); double doubleCheck; //gets double value and returns it if (double.TryParse(cell.getContent().ToString(), out doubleCheck)) { return(doubleCheck); } //gets evaluates formaule and returns is calculated value and returns it bool isFormula = cell.getContent().GetType() == typeof(Formula); if (isFormula) { Formula f = (Formula)cell.getContent(); return(f.Evaluate(lookup)); } //returns string value of cell bool isString = cell.getContent().GetType() == typeof(String); if (isString) { return((String)cell.getContent()); } } //if cell is empty return(""); }
/// <summary> /// Writes the contents of this spreadsheet to the named file using an XML format. /// The XML elements should be structured as follows: /// /// <spreadsheet version="version information goes here"> /// /// <cell> /// <name> /// cell name goes here /// </name> /// <contents> /// cell contents goes here /// </contents> /// </cell> /// /// </spreadsheet> /// /// There should be one cell element for each non-empty cell in the spreadsheet. /// If the cell contains a string, it should be written as the contents. /// If the cell contains a double d, d.ToString() should be written as the contents. /// If the cell contains a Formula f, f.ToString() with "=" prepended should be written as the contents. /// /// If there are any problems opening, writing, or closing the file, the method should throw a /// SpreadsheetReadWriteException with an explanatory message. /// </summary> public override void Save(string filename) { XmlWriterSettings settings = new XmlWriterSettings(); settings.Indent = true; settings.IndentChars = ("\t"); try { //Opens writer and creates a file to write too then closes file using (XmlWriter writer = XmlWriter.Create(filename, settings)) { writer.WriteStartDocument(); writer.WriteStartElement("spreadsheet"); writer.WriteAttributeString(null, "version", null, Version); //goes through dictionary getting names and cells foreach (string name in dictionary.Keys) { cell cell = new cell(); dictionary.TryGetValue(name, out cell); //if empty cell dont write it to xml if (GetCellContents(name) == "") { continue; } writer.WriteStartElement("cell"); writer.WriteElementString("name", name); double doubleCheck; //if double sets that to contents element if (double.TryParse(GetCellContents(name).ToString(), out doubleCheck)) { writer.WriteElementString("contents", doubleCheck.ToString()); writer.WriteEndElement(); } //if formula puts that as element content else if (GetCellContents(name).ToString().ElementAt(0) == '=') { Formula f = (Formula)cell.getContent(); writer.WriteElementString("contents", "=" + f.ToString()); writer.WriteEndElement(); } //if string sets that to element content else if (GetCellContents(name).ToString().ElementAt(0) != '=') { writer.WriteElementString("contents", (String)cell.getContent()); writer.WriteEndElement(); } } //ends document writer.WriteEndDocument(); Changed = false; } } catch { throw new SpreadsheetReadWriteException("Saving file failed, file path may be incorrect"); } }
/// <summary> /// If text is null, throws an ArgumentNullException. /// /// Otherwise, if name is null or invalid, throws an InvalidNameException. /// /// Otherwise, the contents of the named cell becomes text. The method returns a /// set consisting of name plus the names of all other cells whose value depends, /// directly or indirectly, on the named cell. /// /// For example, if name is A1, B1 contains A1*2, and C1 contains B1+A1, the /// set {A1, B1, C1} is returned. /// </summary> protected override ISet <string> SetCellContents(string name, string text) { if (text == null) { throw new ArgumentNullException(); } //if its a valid name create a cell add it to a dictionary and adds it name to the set isValidName(name); cell cell = new cell(); ISet <string> set = new HashSet <string>(); if (!dictionary.ContainsKey(name)) { cell.setContent(text); dictionary.Add(name, cell); set.Add(name); //gets any of the cells that depend on this one and recalculates RecursivlyGetDependents(name, set); GetCellsToRecalculate(set); return(set); } //if cell already exists removes it from the dictionary, and removes its dependencies from the graph else if (dictionary.ContainsKey(name)) { dictionary.TryGetValue(name, out cell); bool isFormula = cell.getContent().GetType() == typeof(Formula); if (isFormula) { Formula f = (Formula)cell.getContent(); foreach (string dependee in f.GetVariables()) { graph.RemoveDependency(dependee, name); } } set.Add(name); //gets any of the cells that depend on this one and recalculates RecursivlyGetDependents(name, set); GetCellsToRecalculate(set); dictionary.Remove(name); cell.setContent(text); dictionary.Add(name, cell); return(set); } return(set); }
/// <summary> /// /// </summary> /// <param name="name"></param> /// <returns></returns> private double lookup(string name) { //if name does not exsists thwos exception if (!dictionary.ContainsKey(name)) { ///this is the bug throw new ArgumentException(); } if (dictionary.ContainsKey(name)) { cell cell = new cell(); dictionary.TryGetValue(name, out cell); double doubleCheck; //if named cell has a double value return it to the formula class if (double.TryParse(cell.getContent().ToString(), out doubleCheck)) { return(doubleCheck); } object value; //if the named cell has its own formula recursivly get its value bool isFormula = cell.getContent().GetType() == typeof(Formula); if (isFormula) { Formula f = (Formula)cell.getContent(); value = f.Evaluate(lookup); if (double.TryParse(value.ToString(), out doubleCheck)) { return(doubleCheck); } //if any of the dependent cells have error it is propagated bool isError = value.GetType() == typeof(FormulaError); if (isError) { throw new ArgumentException(); } } else { throw new ArgumentException(); } } //should never reach here return(0); }
/// <summary> /// If name is null or invalid, throws an InvalidNameException. /// Otherwise, returns the contents (as opposed to the value) of the named cell. The return /// value should be either a string, a double, or a Formula. public override object GetCellContents(string name) { //if the name is valid gets the cell and returns its contents //this method also throws exceptions isValidName(name); name = Normalize(name); //if named cell is present gets it contents if (dictionary.ContainsKey(name)) { cell cell = new cell(); dictionary.TryGetValue(name, out cell); double doubleCheck; //for double content if (cell.getContent().GetType() == typeof(Double)) { return(cell.getContent()); } //for formula content bool isFormula = cell.getContent().GetType() == typeof(Formula); if (isFormula) { Formula f = (Formula)cell.getContent(); return(f); } //for string content bool isString = cell.getContent().GetType() == typeof(String); if (isString) { return((String)cell.getContent()); } } //for empty cell return(""); }
/// <summary> /// Enumerates the names of all the non-empty cells in the spreadsheet. /// </summary> public override IEnumerable <string> GetNamesOfAllNonemptyCells() { LinkedList <string> names = new LinkedList <string>(); foreach (string name in dictionary.Keys) { cell check = new cell(); dictionary.TryGetValue(name, out check); //if content is not empty add to the list if (check.getContent() != "") { names.AddFirst(name); } } return(names); }
/// <summary> /// If the formula parameter is null, throws an ArgumentNullException. /// Otherwise, if name is null or invalid, throws an InvalidNameException. /// Otherwise, if changing the contents of the named cell to be the formula would cause a /// circular dependency, throws a CircularException. (No change is made to the spreadsheet.) /// Otherwise, the contents of the named cell becomes formula. The method returns a /// Set consisting of name plus the names of all other cells whose value depends, /// directly or indirectly, on the named cell. /// /// For example, if name is A1, B1 contains A1*2, and C1 contains B1+A1, the /// set {A1, B1, C1} is returned. /// </summary> protected override ISet <string> SetCellContents(string name, Formula formula) { if (formula == null) { throw new ArgumentNullException(); } //checks if its a valid name isValidName(name); name = Normalize(name); cell cell = new cell(); ISet <string> set = new HashSet <string>(); //if the cell isnt already created for that name create it. if (!dictionary.ContainsKey(name)) { //create cell and add the formula to it cell.setContent(formula); //add the cell to the dictionary the name is the key. dictionary.Add(name, cell); set.Add(name); //sets the variables in the formula as a dependee of the new cell foreach (string dependees in formula.GetVariables()) { graph.AddDependency(dependees, name); } //checks for circular dependency and recalculates the cells nesseccary GetCellsToRecalculate(set); //gets all the dependents of the cell and adds to the set RecursivlyGetDependents(name, set); //checks for circular dependency and recalculates the cells nesseccary GetCellsToRecalculate(set); return(set); } //if the cell is already created remove it from the dictionary else if (dictionary.ContainsKey(name)) { //gets the cell out and removes any dependees from the cell dictionary.TryGetValue(name, out cell); bool isFormula = cell.getContent().GetType() == typeof(Formula); if (isFormula) { Formula f = (Formula)cell.getContent(); foreach (string dependee in f.GetVariables()) { graph.RemoveDependency(dependee, name); } } set.Add(name); //addes new dependees to the cell if any foreach (string dependee in formula.GetVariables()) { graph.AddDependency(dependee, name); } //gets all the dependents of the cell and adds to the set GetCellsToRecalculate(set); RecursivlyGetDependents(name, set); //checks for circular dependency and recalculates the cells nesseccary GetCellsToRecalculate(set); dictionary.Remove(name); //sets the new formula cell.setContent(formula); //adds the new cell to the dictionary dictionary.Add(name, cell); return(set); } return(set); }