Esempio n. 1
0
        /// <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>
        public override ISet <string> SetCellContents(string name, Formula formula)
        {
            if (string.IsNullOrWhiteSpace(name) || !IsValidName(name))
            {
                throw new InvalidNameException();
            }

            if (formula == null)
            {
                throw new ArgumentNullException(nameof(formula), "Formula is null");
            }

            if (!_cells.ContainsKey(name))
            {
                _cells.Add(name, new Cell(name));
            }

            var referencedCellsEnumeration = formula.GetVariables();
            var referencedCells            = referencedCellsEnumeration as string[] ?? referencedCellsEnumeration.ToArray();

            var cell = _cells[name];

            cell.Content = formula;
            cell.Value   = formula.Evaluate(_resolveVariables);
            _depenencyManager.ReplaceDependents(name, referencedCells);

            foreach (var dep in referencedCells)
            {
                //cell.DepenencyManager.AddDependency(dep, name);

                if (_cells.ContainsKey(dep))
                {
                    _depenencyManager.AddDependency(name, dep);
                }
            }

            return(new HashSet <string>(GetCellsToRecalculate(name)));
        }
Esempio n. 2
0
        /// <summary>
        /// If the formula parameter is null, throws an ArgumentNullException.
        ///
        /// Otherwise, if name is null or invalid, throws an InvalidNameException.
        ///
        /// contents of the named cell become a 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, Formula formula)
        {
            LinkedList <string> cellsToRecalc;

            cellsToRecalc = (LinkedList <string>)GetCellsToRecalculate(name);

            //Testing for CircularExceptions, does not affect cells so no need to backup old cell.
            foreach (string el in cellsToRecalc)
            {
                if (formula.GetVariables().Contains(el))
                {
                    throw new CircularException();
                }
            }

            //Replacing cell name with new content and value.
            try
            {
                cells[name] = new Cell(name, formula, formula.Evaluate(lookup));
            }
            catch (System.ArgumentException e)
            {
                cells[name] = new Cell(name, formula, new FormulaError());
            }

            //spreadsheet has changed
            Changed = true;

            //recalculates the dependees of name.
            recalculateDependees(name, cellsToRecalc);

            //replace all dependents of name with new formulas variables.
            dependencies.ReplaceDependents(name, formula.GetVariables());

            //grabs name and dependees(direct and indirect) of name and puts them into a HashSet and returns them.
            return(new HashSet <string>(cellsToRecalc));
        }
Esempio n. 3
0
        /// <summary>
        /// If the 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>
        private ISet <string> SetContents(string name, object content)
        {
            // Make sure the content is not null
            if (content == null)
            {
                throw new ArgumentNullException("Make sure the formula is not null.");
            }

            if (name == null || !Cell.IsValidName(name))
            {
                throw new InvalidNameException();
            }

            // Every time we set the contents, remove all of the dependents and dependees for this name.
            cellRelations.ReplaceDependents(name, new List <string>());

            // Set the value to the content. Value will change if content is a formula.
            object value = content;


            // Now, handle formula-specific actions
            if (content is Formula)
            {
                // First make sure that adding this new content would not create a circular dependency.
                Formula contentAsFormula = (Formula)content;
                checkForCircularDependency(name, contentAsFormula);

                // Add in all of the dependencies for this cell
                List <string> variablesInFormula = contentAsFormula.GetVariables().ToList();
                foreach (string v in variablesInFormula)
                {
                    cellRelations.AddDependency(name, v);
                }

                // Get the value and content prepped for cell creation
                value   = contentAsFormula.Evaluate(lookup);
                content = contentAsFormula.ToString();
            }


            // If the cell already exists, just change the content and value.
            if (cells.ContainsKey(name))
            {
                // If they are setting the content to "", remove the cell.
                if (value.ToString().Equals(""))
                {
                    cells.Remove(name);
                }
                else
                {
                    cells[name].content = content;
                    cells[name].value   = value;
                }
            }
            // Otherwise, create a new cell object with the proper name, content, and value
            // This will also check that the name of the cell is valid or not.
            else
            {
                Cell cellForName = new Cell(name, content, value);
                cells.Add(name, cellForName);
            }

            // Get all of the dependees for the named cell and return them.
            HashSet <string> dependsOnNamedCell = new HashSet <string>()
            {
                name
            };
            List <string> namedCellDependees = GetCellsToRecalculate(name).ToList();

            foreach (string dep in namedCellDependees)
            {
                dependsOnNamedCell.Add(dep);
            }
            return(dependsOnNamedCell);
        }
Esempio n. 4
0
        /// <summary>
        /// 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>
        /// <param name="name"></param>
        /// <param name="formula"></param>
        /// <returns></returns>
        protected override ISet <string> SetCellContents(string name, Formula formula)
        {
            var  ReturnSet      = new HashSet <string>();
            var  NewDependents  = new List <string>();
            var  OldDependees   = new List <string>();
            var  VariableValues = new Dictionary <string, double>();
            bool found          = false;
            bool InGraph        = false;

            //Looks through CellList for the cell called name.
            foreach (Cell cell in CellList)
            {
                if (cell.Name == name)
                {
                    foreach (string var in formula.GetVariables())
                    {
                        NewDependents.Add(var);
                    }

                    foreach (string DependName in GetCellsToRecalculate(name))
                    {
                        if (NewDependents.Contains(DependName))
                        {
                            throw new CircularException(); // Changed b/c circular exception doesn't take an argument
                        }
                        ReturnSet.Add(DependName);
                    }

                    foreach (string s in Graph.GetDependents(name))
                    {
                        InGraph = true;
                    }

                    if (InGraph != true)
                    {
                        foreach (string t in NewDependents)
                        {
                            Graph.AddDependency(name, t);
                        }
                    }
                    else
                    {
                        Graph.ReplaceDependents(name, NewDependents);
                    }

                    cell.Contents = formula;
                    found         = true;
                    break;
                }
            }

            //If the name wasnt in the list already we can add it as a new cell.
            if (found == false)
            {
                Cell newcell = new Cell(name, formula, new FormulaError("One or more variables have an undefined value."));
                CellList.Add(newcell);
                foreach (string var in formula.GetVariables())
                {
                    if (var == name)
                    {
                        throw new CircularException();
                    }
                    else
                    {
                        Graph.AddDependency(name, var);
                    }
                }
                foreach (string var in GetCellsToRecalculate(name))
                {
                    ReturnSet.Add(var);
                }
            }
            Changed = true;
            return(ReturnSet);
        }