/// <summary> /// If name is null or invalid, throws an InvalidNameException. /// /// Otherwise, the contents of the named cell becomes number. 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 cell_name, double number) { string name = Normalize(cell_name); //checks if the name is null or invalid if so throws a new InvalidNameException(); if (name == null || IsValid(name) == false) { throw new InvalidNameException(); } //checks if the cell with the name has been set up, if so this sets the contents of the cell to the number passed in. if (spreadsheet.ContainsKey(name)) { spreadsheet[name].set_contents(number); } //if the cell hasnt been set up this creates a new cell and sets its contents to the number passed in. else { spreadsheet.Add(name, new Cell(name, number, number)); } //creates a hash set for the return ISet. ISet <string> depends = new HashSet <string> { }; //looks through each item in the dependency graph and add them to the hash set to return. foreach (string item in GetCellsToRecalculate(name)) { depends.Add(item); } List <string> dependency_fix = new List <string> { }; spreadsheet[name].set_value(number); foreach (string value in dependency_graph.GetDependees(name)) { dependency_fix.Add(value); } foreach (string key in dependency_fix) { dependency_graph.RemoveDependency(key, name); } IEnumerable <string> recalculate_cells = GetCellsToRecalculate(name); foreach (string cell in recalculate_cells) { if (!(cell == name)) { Formula value_of_formula = (Formula)GetCellContents(cell); spreadsheet[cell].set_value(value_of_formula.Evaluate(Lookup)); } } //returns the hash set with all the dependents of name. return(depends); }
/// <summary> /// Returns and enumeration without duplicates of all the direct dependents of /// the named cell. /// </summary> /// <param name="name">Cell to look for all direct dependents</param> /// <returns>An enumerable collection of direct dependents without duplicates.</returns> protected override IEnumerable <string> GetDirectDependents(string name) { if (name == null) { throw new ArgumentNullException(); } name.isLegalVar(); // Simply get the dependees from the graph. HashSet <string> DirectDependents = new HashSet <string>(Graph.GetDependees(name)); return(DirectDependents); }
/// <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) { IEnumerable <String> dependee_list = dependency_graph.GetDependees(name); dependency_graph.ReplaceDependees(name, formula.GetVariables()); try { HashSet <String> all_dependees = new HashSet <String>(GetCellsToRecalculate(name)); if (cell.ContainsKey(name)) { cell[name] = new Cell(formula, LookupValue); } else { cell.Add(name, new Cell(formula, LookupValue)); } return(all_dependees); } catch (CircularException) { dependency_graph.ReplaceDependees(name, dependee_list); throw new CircularException(); } }
// MODIFIED PROTECTION FOR PS5 /// <summary> /// If 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. /// /// 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) { //backup the part of depGraph that will be modified HashSet <string> backupDependees = new HashSet <string>(depGraph.GetDependees(name)); HashSet <string> dependents; //modify depGraph depGraph.ReplaceDependees(name, formula.GetVariables()); //check for circular dependencies try { dependents = new HashSet <string>(GetCellsToRecalculate(name)); } catch (CircularException exception) { //restore the backup in the chance a circular exception is thrown depGraph.ReplaceDependees(name, backupDependees); throw exception; } SetContents(name, formula); //recalculate potentially changed cells RecalculateCells(GetCellsToRecalculate(name)); return(dependents); }
/// <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) { IEnumerable <string> dependeesList1 = graph.GetDependees(name); graph.ReplaceDependees(name, formula.GetVariables()); try { HashSet <string> dependeeslist2 = new HashSet <string>(GetCellsToRecalculate(name)); Cell newCell = new Cell(formula, valueOfCell); if (spreadsheet.ContainsKey(name)) { spreadsheet[name] = newCell; } else { spreadsheet.Add(name, newCell); } return(dependeeslist2); } catch (CircularException) { graph.ReplaceDependees(name, dependeesList1); throw new CircularException(); } }
/// <summary> /// If name is null, throws an ArgumentNullException. /// /// Otherwise, if name isn't a valid cell name, throws an InvalidNameException. /// /// Otherwise, returns an enumeration, without duplicates, of the names of all cells whose /// values depend directly on the value of the named cell. In other words, returns /// an enumeration, without duplicates, of the names of all cells that contain /// formulas containing name. /// /// For example, suppose that /// A1 contains 3 /// B1 contains the formula A1 * A1 /// C1 contains the formula B1 + A1 /// D1 contains the formula B1 - C1 /// The direct dependents of A1 are B1 and C1 /// </summary> protected override IEnumerable <string> GetDirectDependents(string name) { if (name == null) { throw new ArgumentNullException(); } return(dg.GetDependees(name)); }
/// <summary> /// Called by the SetCellContents functions. /// Decides if a new cell needs to be made, adds it to the dictionary, then updates its contents. /// If the cell's contents are an empty string, removes it from the dictionary. /// </summary> private void AddCell(string name, object filler) { Cell tempCell; if (cells.TryGetValue(name, out tempCell)) { if (filler.Equals("")) { cells.Remove(name); } else { tempCell.Contents = filler; } // Remove all old dependencies associated with this cell List <string> dependees = new List <string>(); foreach (string dependee in dependencies.GetDependees(name)) { dependees.Add(dependee); } foreach (string dependee in dependees) { dependencies.RemoveDependency(dependee, name); } } else if (!filler.Equals("")) { cells.Add(name, new Cell(filler)); } if (filler.GetType().Equals(typeof(Formula))) { Formula formula = (Formula)filler; foreach (string str in formula.GetVariables()) { string dependee = str.ToUpper(); dependencies.AddDependency(dependee, name); } } // Assign values object oldValue = GetCellValue(name); DetermineCellValue(name); try { foreach (string toRecalc in GetCellsToRecalculate(name)) { DetermineCellValue(toRecalc); } } catch (CircularException e) // Reset to old value if the new formula results in a CircularException { AddCell(name, oldValue); throw e; } changed = true; }
/// <summary> /// If name is null, throws an ArgumentNullException. /// /// Otherwise, if name isn't a valid cell name, throws an InvalidNameException. /// /// Otherwise, returns an enumeration, without duplicates, of the names of all cells whose /// values depend directly on the value of the named cell. In other words, returns /// an enumeration, without duplicates, of the names of all cells that contain /// formulas containing name. /// /// For example, suppose that /// A1 contains 3 /// B1 contains the formula A1 * A1 /// C1 contains the formula B1 + A1 /// D1 contains the formula B1 - C1 /// The direct dependents of A1 are B1 and C1 /// </summary> protected override IEnumerable <String> GetDirectDependents(String name) { // checking if parameter name is null if (!(nameValidation(name))) { throw new ArgumentNullException(); } // returning a IEnumerable of all the direct dependents of the given cell name return(DGSpreadsheet.GetDependees(name)); }
//Helper method to remove the dependency of all variables that may have been in the cell private void removeDependencies(string name) { HashSet <string> set = new HashSet <string>(dg.GetDependees(name)); foreach (string el in set) { dg.RemoveDependency(el, name); } cells.Remove(name); valueDictionary.Remove(name); }
/// <summary> /// If name is null, throws an ArgumentNullException. /// /// Otherwise, if name isn't a valid cell name, throws an InvalidNameException. /// /// Otherwise, returns an enumeration, without duplicates, of the names of all cells whose /// values depend directly on the value of the named cell. In other words, returns /// an enumeration, without duplicates, of the names of all cells that contain /// formulas containing name. /// /// For example, suppose that /// A1 contains 3 /// B1 contains the formula A1 * A1 /// C1 contains the formula B1 + A1 /// D1 contains the formula B1 - C1 /// The direct dependents of A1 are B1 and C1 /// </summary> /// <param name="name"></param> /// <returns></returns> protected override IEnumerable <string> GetDirectDependents(string name) { if (name.Equals(null)) { throw new ArgumentNullException(); } if (isValidName(name) == false) { throw new InvalidNameException(); } return(d.GetDependees(name)); }
protected override IEnumerable <string> GetDirectDependees(string name) { if (name == null) { throw new ArgumentNullException(); } if (!ValidVariable(name)) { throw new InvalidNameException(); } return(dependencyGraph.GetDependees(Normalize(name))); }
/// <summary> /// Returns and enumeration without duplicates of all the direct dependents of /// the named cell. /// </summary> /// <param name="name">Cell to look for all direct dependents</param> /// <returns>An enumerable collection of direct dependents without duplicates.</returns> protected override IEnumerable <string> GetDirectDependents(string name) { if (name == null) { throw new ArgumentNullException(); } name = ValidateNormalize(name); // Return the dependees from the graph. HashSet <string> DirectDependents = new HashSet <string>(Graph.GetDependees(name)); return(DirectDependents); }
/// <summary> /// If name is null, throws an ArgumentNullException. /// /// Otherwise, if name isn't a valid cell name, throws an InvalidNameException. /// /// Otherwise, returns an enumeration, without duplicates, of the names of all cells whose /// values depend directly on the value of the named cell. In other words, returns /// an enumeration, without duplicates, of the names of all cells that contain /// formulas containing name. /// /// For example, suppose that /// A1 contains 3 /// B1 contains the formula A1 * A1 /// C1 contains the formula B1 + A1 /// D1 contains the formula B1 - C1 /// The direct dependents of A1 are B1 and C1 /// </summary> protected override IEnumerable <string> GetDirectDependents(string name) { if (name == null) { throw new ArgumentException(); } if (checkName(name) == false) { throw new InvalidNameException(); } else { HashSet <String> result = new HashSet <string>(graph.GetDependees(name)); return(result); } }
/// <summary> /// If name is null, throws an ArgumentNullException. /// /// Otherwise, if name isn't a valid cell name, throws an InvalidNameException. /// /// Otherwise, returns an enumeration, without duplicates, of the names of all cells whose /// values depend directly on the value of the named cell. In other words, returns /// an enumeration, without duplicates, of the names of all cells that contain /// formulas containing name. /// /// For example, suppose that /// A1 contains 3 /// B1 contains the formula A1 * A1 /// C1 contains the formula B1 + A1 /// D1 contains the formula B1 - C1 /// The direct dependents of A1 are B1 and C1 /// </summary> protected override IEnumerable <string> GetDirectDependents(string name) { // Normalize name name = Normalizer(name); if (name == null || !(name.IsValidVariableName())) { throw new InvalidNameException(); } else if (!(Validator(name))) { throw new InvalidNameException(); } return(Graph.GetDependees(name)); }
/// <summary> /// If name is null, throws an ArgumentNullException. /// /// Otherwise, if name isn't a valid cell name, throws an InvalidNameException. /// /// Otherwise, returns an enumeration, without duplicates, of the names of all cells whose /// values depend directly on the value of the named cell. In other words, returns /// an enumeration, without duplicates, of the names of all cells that contain /// formulas containing name. /// /// For example, suppose that /// A1 contains 3 /// B1 contains the formula A1 * A1 /// C1 contains the formula B1 + A1 /// D1 contains the formula B1 - C1 /// The direct dependents of A1 are B1 and C1 /// </summary> protected override IEnumerable <string> GetDirectDependents(string name) { HashSet <string> hs = new HashSet <string>(); //if name is null we throw Argumentnull Exception. if (name == null) { throw new ArgumentNullException(); } //if name is not in corent format we throw invalidNameException. if (!Regex.IsMatch(name, @"^[a-zA-Z]+\d+$")) { throw new InvalidNameException(); } return(DG.GetDependees(name)); }
/// <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. protected override ISet <string> SetCellContents(string name, Formula formula) { if (formula == null) { throw new ArgumentNullException("A cell can't have a null value!);"); } if (name == null || !ValidVariable(name)) { throw new InvalidNameException(); } string normalizedName = Normalize(name); //saving old dependees and contents in case a circular dependency is found List <string> oldDependees = new List <string>(dependencyGraph.GetDependees(normalizedName)); cells.TryGetValue(normalizedName, out var oldContents); //dependees are replaced with dependees (variables) of new formula dependencyGraph.ReplaceDependees(normalizedName, formula.GetVariables()); cells[normalizedName] = new Cell(normalizedName, formula, LookupCellValue); //a circular dependency is checked for, old dependees and content are kept if one is found try { //recalculating necessary cell values List <string> recalculatedCells = new List <string>(GetCellsToRecalculate(normalizedName)); RecalculateCellValues(recalculatedCells); //successful return means spreadsheet is changed Changed = true; return(new HashSet <string>(recalculatedCells)); } catch (CircularException) { if (oldContents != null) { cells[normalizedName] = new Cell(normalizedName, oldContents.Contents, LookupCellValue); } else //if the cell was empty before setting to this invalid formula, leave it empty { cells.Remove(normalizedName); } dependencyGraph.ReplaceDependees(normalizedName, oldDependees); throw; } }
/// <summary> /// returns direct dependents of name. /// If name is null. Throw ArgumentNullException() /// If name isnt a valid cell name. Throw an InvalidNameException. /// </summary> /// <param name="name"></param> /// <returns></returns> protected override IEnumerable <string> GetDirectDependents(string name) { //if name parameter is null, throw ArgumentNullException if (name == null) { throw new ArgumentNullException(); } name = Normalize(name); //if name isnt a valid variable name, throw InvalidNameException if (!isValidVariable(name)) { throw new InvalidNameException(); } //returns direct dependents of name. return(dependencies.GetDependees(name)); }
/// <summary> /// If name is null, throws an ArgumentNullException. /// /// Otherwise, if name isn't a valid cell name, throws an InvalidNameException. /// /// Otherwise, returns an enumeration, without duplicates, of the names of all cells whose /// values depend directly on the value of the named cell. In other words, returns /// an enumeration, without duplicates, of the names of all cells that contain /// formulas containing name. /// /// For example, suppose that /// A1 contains 3 /// B1 contains the formula A1 * A1 /// C1 contains the formula B1 + A1 /// D1 contains the formula B1 - C1 /// The direct dependents of A1 are B1 and C1 /// /// </summary> /// <param name="name">cell name</param> /// <returns></returns> protected override IEnumerable <string> GetDirectDependents(string name) { // check it out, always. //if (name == null) { throw new ArgumentNullException(); } // In PS4, I used regax for check the name's validation. // However, we have delegate 'IsValid' function. // we can check the name using the delegate function //if (!IsValid(name)) { throw new InvalidNameException(); } // we have to normalize the name after checking all exceptions. string normalizedName = Normalize(name); // Now, we can get all dependees form PS2 DependencyGraph, so I declare DG IEnumerable <String> tempDG = DG.GetDependees(name); HashSet <String> dircDependents = new HashSet <string>(tempDG); return(dircDependents); }
/// <summary> /// If name is null, throws an ArgumentNullException. /// /// Otherwise, if name isn't a valid cell name, throws an InvalidNameException. /// /// Otherwise, returns an enumeration, without duplicates, of the names of all cells whose /// values depend directly on the value of the named cell. In other words, returns /// an enumeration, without duplicates, of the names of all cells that contain /// formulas containing name. /// /// For example, suppose that /// A1 contains 3 /// B1 contains the formula A1 * A1 /// C1 contains the formula B1 + A1 /// D1 contains the formula B1 - C1 /// The direct dependents of A1 are B1 and C1 /// </summary> protected override IEnumerable <string> GetDirectDependents(string name) { // If name is null, throws an ArgumentNullException. if (name == null) { throw new ArgumentNullException(); } // Otherwise, if name isn't a valid cell name, throws an InvalidNameException. else if (IsValidps4(name) == false) { throw new InvalidNameException(); } // Otherwise, returns an enumeration, without duplicates, of the names of all cells whose // values depend directly on the value of the named cell. In other words, returns // an enumeration, without duplicates, of the names of all cells that contain // formulas containing name. return(myDG.GetDependees(name)); }
/// <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, and no change is made to the spreadsheet. /// /// Otherwise, the contents of the named cell becomes formula. The method returns a /// list 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 /// list {A1, B1, C1} is returned. /// </summary> protected override IList <string> SetCellContents(string name, Formula formula) { if (formula is null) { throw new ArgumentNullException(); } IEnumerable <string> oldDependencies = dependencies.GetDependees(name); List <string> newDependencies = new List <string>(); foreach (string x in formula.GetVariables()) { newDependencies.Add(x); } dependencies.ReplaceDependees(name, newDependencies); List <string> listToReturn = new List <string>(); try { listToReturn = getDependents(name); } catch { dependencies.ReplaceDependees(name, oldDependencies); throw new CircularException(); } Changed = true; if (spreadSheetCells.TryGetValue(name, out Cell cell)) { cell.setCellContents(formula); return(listToReturn); } else { spreadSheetCells.Add(name, new Cell(name, formula)); return(listToReturn); } }
/// <summary> /// Updates a cell with the given contents. /// Updates formula dependencies where needed. /// </summary> /// <param name="name">The name of the cell to update.</param> /// <param name="contents">The new contents of the cell.</param> /// <returns>The cells which depend on the updated cell, either directly or indirectly.</returns> private ISet <string> UpdateCell(string name, object contents) { // Holds the cells which need to be recalculated. ISet <string> cellsToRecalculate; // Dependencies of formulas must be updated in the graph. if (contents is Formula formula) { // Keep track of the old dependees var oldDependees = _formulaCellDependencyGraph.GetDependees(name); // Replace the old dependees with the new dependees. _formulaCellDependencyGraph.ReplaceDependees(name, formula.GetVariables()); // Check for a circular dependency. try { cellsToRecalculate = new HashSet <string>(GetCellsToRecalculate(name)); } catch (CircularException) { // Restore old dependees upon a circular exception so that nothing is modified. _formulaCellDependencyGraph.ReplaceDependees(name, oldDependees); throw; } } else { // Clear any old dependees in the graph _formulaCellDependencyGraph.ReplaceDependees(name, new string[0]); // Find cells to re-calculate. cellsToRecalculate = new HashSet <string>(GetCellsToRecalculate(name)); } if (contents is string text && text == "") { // If text is empty, the cell should be removed from the dictionary. _cells.Remove(name); }
/// <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) { // Dead code due to requirements for SetContentsOfCell //if (ReferenceEquals(formula, null)) //throw new ArgumentNullException(); // Dead code due to requirements for SetContentsOfCell //(ReferenceEquals(name, null) || !(IsValidName(name))) // throw new InvalidNameException(); // temp variable to hold old dependents IEnumerable <String> old_dependees = dg.GetDependees(name); // replace the dependents of 'name' in the dependency graph with the variables in formula dg.ReplaceDependees(name, formula.GetVariables()); try // check if the new depdendency graph creates a circular reference { // if there is no exception HashSet <String> all_dependees = new HashSet <String>(GetCellsToRecalculate(name)); // create a new cell Cell cell = new Cell(formula, LookupValue); if (cells.ContainsKey(name)) // if it already contains that key { cells[name] = cell; // replace the key with the new value } else { cells.Add(name, cell); // otherwise add a new key for that value } return(all_dependees); } catch (CircularException e) // if an exception is caught, we want to keep the old dependents and not change the cell { dg.ReplaceDependees(name, old_dependees); throw new CircularException(); } }
/// <summary> /// A convenience method for invoking the other version of GetCellsToRecalculate /// with a singleton set of names. See the other version for details. /// </summary> protected override IEnumerable <string> GetDirectDependents(string name) { return(dependency.GetDependees(name)); }
/// <summary> /// Requires that all of the variables in formula are valid cell names. /// /// 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. /// /// 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 (!IsValidCellName(name, IsValid)) { throw new InvalidNameException(); } if (!Cells.ContainsKey(name)) { Cells.Add(name, new Cell()); } // Set consisting of variables in formula ISet <string> variables = formula.GetVariables(); object oldVal = Cells[name.ToUpper()].GetContent(); bool hadFormula = Cells[name.ToUpper()].hasFormula; Cells[name.ToUpper()].SetContent(formula); // Remove dependess that aren't there in the formula if (Graph.HasDependees(name)) { foreach (string dependee in Graph.GetDependees(name).ToList()) { if (!variables.Contains(dependee)) { Graph.RemoveDependency(dependee, name); } } } // Add dependees that don't already exist foreach (string variable in variables) { Graph.AddDependency(variable, name); } ISet <string> changedSet = new HashSet <string>(); changedSet = GetAllRelatedDependents(name); // changedSet.Add(name); // if (Graph.HasDependents(name)) // { // foreach (string dependent in Graph.GetDependents(name)) // { // changedSet.Add(dependent); // } // } // To check for Circular Dependency try { GetCellsToRecalculate(changedSet); } catch (CircularException e) { Cells[name.ToUpper()].SetContent(oldVal); Cells[name.ToUpper()].hasFormula = hadFormula; throw e; } return(changedSet); }
protected override IEnumerable <String> GetDirectDependents(String name) { return(ssDep.GetDependees(name)); }
/// <summary> /// Requires that all of the variables in formula are valid cell names. /// /// 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. /// /// 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) { // check if name is null or invalid if (!Regex.IsMatch(name, IsValid.ToString()) || ReferenceEquals(name, null) || !Regex.IsMatch(name, @"^[a-zA-Z_](?: [a-zA-Z_]|\d)*$")) { throw new InvalidNameException(); } IEnumerable <String> dependees = dg.GetDependees(name); // replace dependents of name with the formula variables dg.ReplaceDependees(name, formula.GetVariables()); //check if dependency graph produces circular dependency try { HashSet <String> hsDependees = new HashSet <String>(GetCellsToRecalculate(name)); Cell cell = new Cell(formula); cell.value = formula; // if cell does not contain name, add new key for the value. // if it does contain name, then replace key with the value if (!cells.ContainsKey(name)) { cells.Add(name, new Cell(formula)); } else { cells[name] = new Cell(formula); } foreach (string values in new HashSet <String>(GetCellsToRecalculate(name))) { if (!(cells[values].contents is Formula)) { cell.value = formula.Evaluate((Lookup)LookupValue); } else { try { Formula f = (Formula)cells[values].contents; double value = f.Evaluate((Lookup)LookupValue); cells[values].value = value; } catch (Exception e) { cells[values].value = new FormulaError(); } } } return(new HashSet <String>(GetCellsToRecalculate(name))); } // if exception is caught, keep old dependents catch (CircularException e) { dg.ReplaceDependees(name, dependees); throw new CircularException(); } }
/// <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> /// <param name="name"></param> /// <param name="text"></param> /// <returns></returns> protected override ISet <string> SetCellContents(string name, string text) { var ReturnSet = new HashSet <string>(); var OldDependents = new List <string>(); bool found = false; if (text == null) { throw new ArgumentNullException(); } //Looks through CellList for the cell called name. foreach (Cell cell in CellList) { if (cell.Name == name) { // If the replacement text is an empty string we are emptying the cell, otherwise we are changing a cell to be used. if (text != string.Empty) { foreach (string DependName in GetCellsToRecalculate(name)) { ReturnSet.Add(DependName); } //Since we found that the cell already existed, replace the contents and replace any pre-exisiting dependents. cell.Contents = text; cell.Value = text; foreach (string dependent in Graph.GetDependents(name)) { OldDependents.Add(dependent); } foreach (string t in OldDependents) { Graph.RemoveDependency(name, t); } found = true; break; } else { //Example. //A1 contains 3 //A2 contains 5 //A3 contains A1 + A2 //A4 contains A3*2 //Replacing A3 with an empty text should remove from the graph that it has dependees A1 and A2, but do nothing about A4. foreach (string DependName in GetCellsToRecalculate(name)) { ReturnSet.Add(DependName); } CellList.Remove(cell); foreach (string dep in Graph.GetDependees(cell.Name)) { Graph.RemoveDependency(cell.Name, dep); } found = true; break; } } } //If the name wasnt in the list already we can add it as a new cell. //Fix the value in the constructor later. if (found == false) { if (text != string.Empty) { Cell newcell = new Cell(name, text, text); CellList.Add(newcell); foreach (string var in GetCellsToRecalculate(name)) { ReturnSet.Add(var); } } } Changed = true; return(ReturnSet); }
protected override ISet <string> SetCellContents(string name, double number) { // If the cell already exists, remove it if (spreadsheetCells.ContainsKey(name)) { spreadsheetCells.Remove(name); } // Create new cell Cell toBeAdded = new Cell(); // Set cellName equal to name toBeAdded.cellName = name; // Set cellContents equal to number toBeAdded.cellContents = number; // Set cellValue equal to number toBeAdded.cellValue = number; // Set cellContentsType equal to double toBeAdded.cellContentsType = "double"; // Add (name, cell) to our spreadsheetCells dictionary spreadsheetCells.Add(name, toBeAdded); // Get dependecies for return portion of method call HashSet <String> returnValues = new HashSet <String>(); // Call GetCellsToRecalculate to get direct dependents IEnumerable dependents = GetCellsToRecalculate(name); foreach (String temp in dependents) { // Add direct dependents to returnValues returnValues.Add(temp); } // Call GetDependees on dependencies to get indirect dependents IEnumerable dependees = dependencies.GetDependees(name); foreach (String temp in dependees) { // Add indirect dependents to returnValues returnValues.Add(temp); } // Recalculate Cell recalculation; foreach (String depend in dependents) { if (spreadsheetCells.TryGetValue(depend, out recalculation)) { // Set value of cell try { String equalPattern = @"^="; String cellContents = recalculation.cellContents.ToString(); if (Regex.IsMatch(cellContents, equalPattern)) { String parsedContents = cellContents.Substring(1); Formula f = new Formula(parsedContents); recalculation.cellValue = f.Evaluate((x) => (double)GetCellValue(x)); //SetContentsOfCell(recalculation.cellName, recalculation.cellContents.ToString()); } } catch (InvalidCastException) { recalculation.cellValue = new FormulaError(); } catch (FormulaEvaluationException) { recalculation.cellValue = new FormulaError(); } } } // Change changed to true since we made a change to the spreadsheet Changed = true; // Return return(returnValues); }