private void UpdateGrid(VariableStat stat)
        {
            DataGridViewRow row = gridView.Rows[stat.GridRowIdx];

            row.Cells[0].Value = stat.QVWName;
            row.Cells[1].Value = stat.NumVariables;
            row.Cells[2].Value = stat.NumUsed;
            row.Cells[3].Value = stat.NumUses;
            row.Cells[4].Value = stat.NumUnUsed;
            gridView.Refresh();
        }
        private void UpdateSingleProject(string target, string folder, string qvwName)
        {
            string[]        lines;
            List <string>   variables       = new List <string>();
            List <string>   objectList      = new List <string>();
            List <Variable> variableDetails = new List <Variable>();

            // Open the target and read all Variables
            lines = File.ReadAllLines(target);

            int startVariables = Array.IndexOf(lines, startTag) + 1;
            int endVariables   = Array.LastIndexOf(lines, endTag);

            // Read each Variable name
            for (int i = startVariables; i < endVariables; i++)
            {
                // Ignore lines where start and end tags are on the same line
                if (lines[i].Contains(startTag) && !lines[i].Contains(endTag.Trim()))
                {
                    string varName = lines[i + 1].Replace("<Name>", "").Replace("</Name>", "").Trim();
                    if (reservedVariables == null || !reservedVariables.Contains(varName))
                    {
                        variables.Add(varName);
                    }
                }
            }

            variableProgressBar.Maximum = variables.Count();
            variableProgressBar.Step    = 1;
            variableProgressBar.Value   = 0;

            DataGridViewRow row = (DataGridViewRow)gridView.RowTemplate.Clone();

            row.CreateCells(gridView, qvwName, variables.Count(), 0, 0, 0);
            int idx = gridView.Rows.Add(row);

            variableStats.Add(new VariableStat
            {
                QVWName      = qvwName,
                NumVariables = variables.Count(),
                NumUsed      = 0,
                NumUses      = 0,
                NumUnUsed    = 0,
                GridRowIdx   = idx
            });
            VariableStat stat = (from v in variableStats
                                 where v.QVWName.Equals(qvwName)
                                 select v).First();

            objectList.AddRange(Directory.GetFiles(folder, "*.xml").ToList <string>());
            objectList.AddRange(Directory.GetFiles(folder, "*.txt").ToList <string>());

            // Open and chech each object for presence of any variables.
            // When found, record the name of the object and line number variable was found
            objectProgressBar.Maximum = objectList.Count();
            objectProgressBar.Step    = 1;
            objectProgressBar.Value   = 0;

            int objectIdx = 0;

            foreach (string objectName in objectList)
            {
                string objectNameOnly = objectName.Replace(folder + "\\", "").Replace(".xml", "");
                objectIdx++;
                objectTextBox.Text = objectNameOnly;
                objectTextBox.Refresh();
                objectCountTextBox.Text = string.Format("{0} / {1}", objectIdx, objectList.Count());
                objectCountTextBox.Refresh();
                objectProgressBar.PerformStep();

                if (objectName.Contains("AllProperties.xml") ||
                    objectName.Contains("DocProperties.xml") ||
                    objectName.Contains("DocInternals.xml"))
                {
                    continue;
                }

                bool   inBase64     = false;
                string base64EndTag = "";

                lines = File.ReadAllLines(objectName);
                StringBuilder sb = new StringBuilder();
                for (int i = 0; i < lines.Length; i++)
                {
                    // Ignore comment lines
                    if (lines[i].Trim().StartsWith("//"))
                    {
                        continue;
                    }

                    if (lines[i].Contains("enctype=\"base64\""))
                    {
                        // If the end tag is on same line as start tag, skip it.
                        if (lines[i].Contains("base64\"></"))
                        {
                            continue;
                        }

                        inBase64     = true;
                        base64EndTag = lines[i].Replace(" enctype=\"base64\"", "").Trim().Replace("<", "</");
                        continue;
                    }

                    if (inBase64)
                    {
                        if (lines[i].Contains(base64EndTag))
                        {
                            inBase64 = false;
                        }
                        continue;
                    }

                    Application.DoEvents();
                    sb.AppendLine(lines[i]);
                }
                string allLines = sb.ToString();
                variableProgressBar.Value = 0;
                for (int j = 0; j < variables.Count; j++)
                {
                    variableTextBox.Text = variables[j];
                    variableTextBox.Refresh();
                    variableProgressBar.PerformStep();
                    Match m = Regex.Match(allLines, string.Format("\\b{0}\\b", variables[j]));
                    while (m.Success)
                    {
                        Variable variable = (from v in variableDetails
                                             where v.VariableName.Equals(variables[j])
                                             select v).FirstOrDefault();


                        stat.NumUses++;
                        // Only increment the number used if it is the first time the variable has been seen as used
                        if (variable == null)
                        {
                            stat.NumUsed++;
                        }

                        variableDetails.Add(new Variable
                        {
                            VariableName = variables[j],
                            IsUsed       = true,
                            ObjectName   = objectNameOnly
                        });
                        if (stat.NumUses % 10 == 0)
                        {
                            UpdateGrid(stat);
                        }
                        Application.DoEvents();
                        m = m.NextMatch();
                    }
                }
                // Update the grid after every object scanned.
                UpdateGrid(stat);
            }
            // For each used variable, determine what sheet the object is on
            lines = File.ReadAllLines(folder + "\\QlikViewProject.xml");
            int startSheets = Array.IndexOf(lines, "  <SHEETS>") + 1;
            int endSheets   = Array.LastIndexOf(lines, "  </SHEETS>");

            foreach (Variable variable in variableDetails)
            {
                if (string.IsNullOrEmpty(variable.ObjectName))
                {
                    continue;
                }

                if (variable.ObjectName.StartsWith("SH"))
                {
                    variable.SheetName = variable.ObjectName;
                    continue;
                }
                string currentSheet = "";
                for (int i = startSheets; i < endSheets; i++)
                {
                    if (lines[i].Contains("<SheetId>"))
                    {
                        currentSheet = lines[i].Replace("<SheetId>Document\\", "").Replace("</SheetId>", "").Trim();
                        continue;
                    }
                    if (lines[i].Contains(variable.ObjectName + "</ObjectId>"))
                    {
                        variable.SheetName = currentSheet;
                        break;
                    }
                }
            }

            // Add Variables to the list that are unused
            //VariableStat stat = (from v in variableStats
            //                     where v.QVWName.Equals(qvwName)
            //                     select v).First();
            foreach (string variable in variables)
            {
                Variable varItem = (from v in variableDetails
                                    where v.VariableName.Equals(variable)
                                    select v).FirstOrDefault();
                if (varItem == null)
                {
                    variableDetails.Add(new Variable
                    {
                        VariableName = variable,
                        IsUsed       = false
                    });
                    stat.NumUnUsed++;
                    UpdateGrid(stat);
                }
            }

            // Write out variable usage report
            string fileName = folder.Replace("-prj", "-VariableUsage.txt");

            using (StreamWriter sw = new StreamWriter(fileName))
            {
                sw.WriteLine("Used?\tName\tSheet\tObject");
                foreach (Variable item in variableDetails)
                {
                    sw.WriteLine(string.Format("{0}\t{1}\t{2}\t{3}", (item.IsUsed ? "Yes" : "No"), item.VariableName, item.SheetName, item.ObjectName));
                }
            }

            // Update display
            UpdateResults("    See " + fileName + " for results");
            if (stat.NumUnUsed > 0)
            {
                DialogResult dr = MessageBox.Show("Mapping Results are Saved in " + fileName + Environment.NewLine + Environment.NewLine +
                                                  "Delete Unused Variables from " + qvwName + "?", "Variable Mapping", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2);
                if (dr == DialogResult.Yes)
                {
                    DeleteUnusedVariables(target, variableDetails);
                }
            }
        }