protected override ISet <String> SetCellContents(String name, Formula formula) { //EXCEPTION HANDELING\\ if (System.String.IsNullOrWhiteSpace(name)) { throw new InvalidNameException(); } if (!isValid(name)) { throw new InvalidNameException(); } if (formula == null) { throw new ArgumentNullException(); } this.temp = new HashSet <string>(); foreach (string s in formula.GetVariables()) //GET ALL THE VARIABLES FROM THE FORMULA AND ADD THEM TO A SET { if (!isValid(s)) { throw new FormulaFormatException("One or more variables names do not follow the proper syntax expected"); } this.temp.Add(s); } foreach (string s in this.temp) //TRACK DEPENDENCIES { if (ssDep.HasDependents(s)) { foreach (string ss in ssDep.GetDependents(s)) { if (ss == s || ss == name) { throw new CircularException(); } } } ssDep.AddDependency(name, s); } Cell v; if (Cells.TryGetValue(name, out v)) //Get the right cell { if (v.Content is Formula) { Formula check = (Formula)v.Content; foreach (string s in check.GetVariables()) { ssDep.RemoveDependency(name, s); //Remove old dependencies } } } ISet <string> set = Set(name, formula); foreach (string s in set) //Recalculate Cells that depend on new cells content { calculateV(s); } return(set); }
/// <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 ISet <string> SetCellContents(string name, Formula formula) { // Parse the formula to get the variables IEnumerable variables = formula.GetVariables(); // Get features of cell prior to removing it in case there is a circular dependency Cell beforeCircleCheck = new Cell(); Object contents = new Object(); if (spreadsheetCells.TryGetValue(name, out beforeCircleCheck)) { contents = beforeCircleCheck.cellContents; } // If the cell already exists, remove it if (spreadsheetCells.ContainsKey(name)) { spreadsheetCells.Remove(name); foreach (String variable in variables) { dependencies.RemoveDependency(name, variable); } } // Create new cell object Cell toBeAdded = new Cell(); // Set cellName equal to name toBeAdded.cellName = name; // Set cellContents eequal to formula toBeAdded.cellContents = "=" + formula; // Set cellContentsType equal to formula toBeAdded.cellContentsType = "formula"; // Add (name, cell) to spreadsheetCells dictionary spreadsheetCells.Add(name, toBeAdded); // Add to dependency Graph foreach (String variable in variables) { dependencies.AddDependency(name, variable); } // Check for circular dependencies. If one is found, restore origional cell try { GetCellsToRecalculate(name); } catch (CircularException e) { // Restore origional cell if (!(beforeCircleCheck == null)) { spreadsheetCells.Remove(name); foreach (String var in variables) { dependencies.AddDependency(name, var); } toBeAdded.cellContents = beforeCircleCheck.cellContents; spreadsheetCells.Add(name, toBeAdded); } throw e; } // Set value of cell try { toBeAdded.cellValue = formula.Evaluate((x) => (double)GetCellValue(x)); } catch (InvalidCastException) { toBeAdded.cellValue = new FormulaError(); } catch (FormulaEvaluationException) { toBeAdded.cellValue = new FormulaError(); } // Get dependencies for return method call HashSet <String> returnValues = new HashSet <String>(); // Call GetCellsToRecalculate for 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 indriect 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 { recalculation.cellValue = formula.Evaluate((x) => (double)GetCellValue(x)); } 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); }