/// <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> /// <param name="name"></param> /// <param name="formula"></param> /// <returns></returns> protected override ISet<string> SetCellContents(string name, SpreadsheetUtilities.Formula formula) { //first of all normalize name name = Normalize(name); if (formula == null) throw new ArgumentNullException(); if (name == null || !Name_Verify(name)) throw new InvalidNameException(); //HadAdd is used to monitoring which dependent is added in DependGraph, if circularexception occur, delete all the //dependent which is been add in the DependGraph List<string> HadAdd = new List<string>(); //check if the new formula contain a circulardepent foreach (string s in formula.GetVariables()) { //make sure that dependent(s,name) is not in the graph_dependent then we add them into the graph_dependent if (!new HashSet<string>(Spreadsheet_DependGraph.GetDependents(s)).Contains(name)) { HadAdd.Add(s); Spreadsheet_DependGraph.AddDependency(s, name); } try { //use getCellTorecalcualte function to test if the circular dependency exist GetCellsToRecalculate(name); } catch (CircularException ce) { //if the circular dependency exist remove the dependency which you have add and throw an exception foreach (string s1 in HadAdd) { Spreadsheet_DependGraph.RemoveDependency(s1, name); } throw ce; } } //set the named cell's value to the value. cell A_cell; Spreadsheet_cells.TryGetValue(name, out A_cell); if (A_cell == null) { A_cell = new cell(); A_cell.name = name; A_cell.content = (object)formula; A_cell.value = formula.Evaluate(lookup); Spreadsheet_cells.Add(A_cell.name, A_cell); } else { A_cell.content = (object)formula; A_cell.value = formula.Evaluate(lookup); Spreadsheet_cells.Remove(A_cell.name); Spreadsheet_cells.Add(A_cell.name, A_cell); } //recalculate all the direct and indirect cells' value foreach (string s in GetCellsToRecalculate(name)) { if (s == name) continue; cell cell1; Spreadsheet_cells.TryGetValue(s, out cell1); cell1.value = ((Formula)cell1.content).Evaluate(lookup); Spreadsheet_cells.Remove(s); Spreadsheet_cells.Add(s, cell1); } //define that the spreadsheet is changed Changed = true; return new HashSet<string>(GetCellsToRecalculate(name)); }
/// <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) { //first of all normalize name name = Normalize(name); if (text == null) throw new ArgumentNullException(); if (name == null || !Name_Verify(name)) throw new InvalidNameException(); //set the named cell's value to the value. cell A_cell; Spreadsheet_cells.TryGetValue(name, out A_cell); if (A_cell == null) { A_cell = new cell(); A_cell.name = name; A_cell.content = (object)text; A_cell.value = (object)text; Spreadsheet_cells.Add(A_cell.name, A_cell); } else { A_cell.content = (object)text; A_cell.value = (object)text; Spreadsheet_cells.Remove(A_cell.name); Spreadsheet_cells.Add(A_cell.name, A_cell); } //remove all the dependee it has foreach (string s in Spreadsheet_DependGraph.GetDependees(name)) { Spreadsheet_DependGraph.RemoveDependency(s, name); } //recalculate all the direct and indirect cells' value foreach (string s in GetCellsToRecalculate(name)) { if (s == name) continue; cell cell1; Spreadsheet_cells.TryGetValue(s, out cell1); cell1.value = ((Formula)cell1.content).Evaluate(lookup); Spreadsheet_cells.Remove(s); Spreadsheet_cells.Add(s, cell1); } //define that the spreadsheet is changed Changed = true; //get all the value dependent on named cell using helper method Visit return new HashSet<string>(GetCellsToRecalculate(name)); }