/// <summary> /// Creates an empty Spreadsheet whose IsValid regular expression accepts every string. /// </summary> public Spreadsheet() { sheet = new Dictionary <string, Cell>(); graph = new Dependencies.DependencyGraph(); isValid = new Regex(""); Changed = false; }
/// <summary> /// Creates a Spreadsheet that is a duplicate of the spreadsheet saved in source. /// See the AbstractSpreadsheet.Save method and Spreadsheet.xsd for the file format /// specification. If there's a problem reading source, throws an IOException /// If the contents of source are not consistent with the schema in Spreadsheet.xsd, /// throws a SpreadsheetReadException. If there is an invalid cell name, or a /// duplicate cell name, or an invalid formula in the source, throws a SpreadsheetReadException. /// If there's a Formula that causes a circular dependency, throws a SpreadsheetReadException. /// </summary> public Spreadsheet(TextReader source) { sheet = new Dictionary <string, Cell>(); graph = new Dependencies.DependencyGraph(); XmlSchemaSet sc = new XmlSchemaSet(); sc.Add(null, "Spreadsheet.xsd"); XmlReaderSettings settings = new XmlReaderSettings(); settings.ValidationType = ValidationType.Schema; settings.Schemas = sc; settings.ValidationEventHandler += ValidationCallback; using (XmlReader reader = XmlReader.Create(source, settings)) { while (reader.Read()) { if (reader.IsStartElement()) { switch (reader.Name) { case "spreadsheet": isValid = new Regex(reader["IsValid"]); break; case "cell": try { if (sheet.ContainsKey(reader["name"])) { throw new InvalidDataException(); } SetContentsOfCell(reader["name"], reader["contents"]); } catch (InvalidNameException) { throw new SpreadsheetReadException("Invalid name in source file: " + reader["name"]); } catch (CircularException) { throw new SpreadsheetReadException("Formula causes circular dependency: " + reader["contents"]); } catch (FormulaFormatException) { throw new SpreadsheetReadException("Invalid formula in source file: " + reader["contents"]); } catch (InvalidDataException) { throw new SpreadsheetReadException("Source file has duplicate cell name: " + reader["name"]); } break; } } } } Changed = false; }
/// <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) { if (formula.Equals(null)) { throw new ArgumentNullException(); } if (!isValidName(name)) { throw new InvalidNameException(); } name = name.ToUpper(); formula = new Formula(formula.ToString().ToUpper()); if (!sheet.ContainsKey(name)) { sheet.Add(name, new Cell(name, "")); } Dependencies.DependencyGraph tempGraph = new Dependencies.DependencyGraph(graph); Cell c; HashSet <string> set = new HashSet <string>(); graph.ReplaceDependees(name, formula.GetVariables()); try { foreach (string s in GetCellsToRecalculate(name)) { set.Add(s); } } catch (CircularException) { graph = tempGraph; throw new CircularException(); } if (sheet.TryGetValue(name, out c)) { c.SetContents(formula); sheet[name] = c; } UpdateValue(set); return(set); }