コード例 #1
0
ファイル: ImageDataXml.cs プロジェクト: ben-norton/Timelapse
        // Reads all the data from the old ImageData.xml files into the imageData structure from the XML file in the filepath.
        // Note that we need to know the code controls,as we have to associate any points read in with a particular counter control
        public static Tuple <int, int> Read(string filePath, FileDatabase imageDatabase)
        {
            // XML Preparation - follows CA3075  pattern for loading
            XmlDocument xmlDoc = new XmlDocument()
            {
                XmlResolver = null
            };

            System.IO.StringReader sreader = new System.IO.StringReader(File.ReadAllText(filePath));
            XmlReader reader = XmlReader.Create(sreader, new XmlReaderSettings()
            {
                XmlResolver = null
            });

            xmlDoc.Load(reader);

            // Import the old log (if any)
            XmlNodeList logNodes = xmlDoc.SelectNodes(Constant.ImageXml.Images + Constant.ImageXml.Slash + Constant.DatabaseColumn.Log);

            if (logNodes.Count > 0)
            {
                XmlNode logNode = logNodes[0];
                imageDatabase.ImageSet.Log = logNode.InnerText;
                imageDatabase.UpdateSyncImageSetToDatabase();
            }

            // Create three lists, each one representing the datalabels (in order found in the template) of notes, counters and choices
            // We will use these to find the matching ones in the xml data table.
            List <string> noteControlNames    = new List <string>();
            List <string> counterControlNames = new List <string>();
            List <string> choiceControlNames  = new List <string>();

            foreach (ControlRow control in imageDatabase.Controls)
            {
                // Note that code should be modified to  deal with flag controls
                switch (control.Type)
                {
                case Constant.Control.Counter:
                    counterControlNames.Add(control.DataLabel);
                    break;

                case Constant.Control.FixedChoice:
                    choiceControlNames.Add(control.DataLabel);
                    break;

                case Constant.Control.Note:
                    noteControlNames.Add(control.DataLabel);
                    break;

                default:

                    break;
                }
            }

            XmlNodeList  nodeList         = xmlDoc.SelectNodes(Constant.ImageXml.Images + Constant.ImageXml.Slash + Constant.DatabaseColumn.Image);
            int          imageID          = 0;
            TimeZoneInfo imageSetTimeZone = imageDatabase.ImageSet.GetSystemTimeZone();
            List <ColumnTuplesWithWhere> imagesToUpdate  = new List <ColumnTuplesWithWhere>();
            List <ColumnTuplesWithWhere> markersToUpdate = new List <ColumnTuplesWithWhere>();
            List <Tuple <string, List <ColumnTuple> > > fileNamesMarkersList = new List <Tuple <string, List <ColumnTuple> > >();

            int successCounter = 0;
            int skippedCounter = 0;

            foreach (XmlNode node in nodeList)
            {
                imageID++;

                // We ignore:
                // - Folder and Relative path, as the new template will have the correct values
                // - ImageQuality, as the new Timelapse version probably has a better determination of it
                // - DeleteFlag, as the old-style xml templates didn't have them
                // - Flags as the old-style xml templates didn't have them

                List <ColumnTuple> columnsToUpdate = new List <ColumnTuple>(); // Populate the data
                // File Field - We use the file name as a key into a particular database row. We don't change the database field as it is our key.
                string imageFileName = node[Constant.ImageXml.File].InnerText;

                // If the Folder Path differs from where we had previously loaded it,
                // warn the user that the new path will be substituted in its place
                // This gets the folderName in the Xml file, but we still ahve to get the folderName as it currently exists.
                // string folderName = node[Constant.ImageXml.Folder].InnerText;

                // Date - We use the original date, as the analyst may have adjusted them
                string date = node[Constant.ImageXml.Date].InnerText;
                columnsToUpdate.Add(new ColumnTuple(Constant.DatabaseColumn.Date, date));

                // Date - We use the original time, although its almost certainly identical
                string time = node[Constant.ImageXml.Time].InnerText;
                columnsToUpdate.Add(new ColumnTuple(Constant.DatabaseColumn.Time, time));

                // DateTime
                if (DateTimeHandler.TryParseLegacyDateTime(date, time, imageSetTimeZone, out DateTimeOffset dateTime))
                {
                    columnsToUpdate.Add(new ColumnTuple(Constant.DatabaseColumn.DateTime, dateTime.UtcDateTime));
                    columnsToUpdate.Add(new ColumnTuple(Constant.DatabaseColumn.UtcOffset, dateTime.Offset));
                }

                // Notes: Iterate through
                int         innerNodeIndex = 0;
                XmlNodeList innerNodeList  = node.SelectNodes(Constant.Control.Note);
                foreach (XmlNode innerNode in innerNodeList)
                {
                    // System.Diagnostics.Debug.Print("Note: " + noteControlNames[innerNodeIndex] + " | " + innerNode.InnerText);
                    columnsToUpdate.Add(new ColumnTuple(noteControlNames[innerNodeIndex++], innerNode.InnerText));
                }

                // Choices: Iterate through
                innerNodeIndex = 0;
                innerNodeList  = node.SelectNodes(Constant.Control.FixedChoice);
                foreach (XmlNode innerNode in innerNodeList)
                {
                    // System.Diagnostics.Debug.Print("Choice: " + choiceControlNames[innerNodeIndex] + " | " + innerNode.InnerText);
                    columnsToUpdate.Add(new ColumnTuple(choiceControlNames[innerNodeIndex++], innerNode.InnerText));
                }

                // Counters: Iterate through
                List <ColumnTuple> counterCoordinates = new List <ColumnTuple>();
                innerNodeIndex = 0;
                innerNodeList  = node.SelectNodes(Constant.Control.Counter);
                foreach (XmlNode innerNode in innerNodeList)
                {
                    // Add the value of each counter to the dataline
                    XmlNodeList dataNode = innerNode.SelectNodes(Constant.DatabaseColumn.Data);
                    // System.Diagnostics.Debug.Print("Counter: " + counterControlNames[innerNodeIndex] + " | " + dataNode[0].InnerText);
                    columnsToUpdate.Add(new ColumnTuple(counterControlNames[innerNodeIndex], dataNode[0].InnerText));

                    // For each counter, find the points associated with it and compose them together as x1,y1|x2,y2|...|xn,yn
                    XmlNodeList pointNodeList = innerNode.SelectNodes(Constant.DatabaseColumn.Point);
                    string      countercoord  = String.Empty;
                    foreach (XmlNode pointNode in pointNodeList)
                    {
                        String x = pointNode.SelectSingleNode(Constant.DatabaseColumn.X).InnerText;
                        if (x.Length > 5)
                        {
                            x = x.Substring(0, 5);
                        }
                        String y = pointNode.SelectSingleNode(Constant.DatabaseColumn.Y).InnerText;
                        if (y.Length > 5)
                        {
                            y = y.Substring(0, 5);
                        }
                        countercoord += x + "," + y + "|";
                    }

                    // Remove the last "|" from the point list
                    if (!String.IsNullOrEmpty(countercoord))
                    {
                        countercoord = countercoord.Remove(countercoord.Length - 1); // Remove the last "|"
                    }

                    // Countercoords will have a list of points (possibly empty) with each list entry representing a control
                    counterCoordinates.Add(new ColumnTuple(counterControlNames[innerNodeIndex], countercoord));
                    innerNodeIndex++;
                }

                // add this image's updates to the update lists
                ColumnTuplesWithWhere imageToUpdate = new ColumnTuplesWithWhere(columnsToUpdate);
                // Since Timelapse1 didn't have relative paths, we only need to set Where using the image filename
                // imageToUpdate.SetWhere(currentFolderName, null, imageFileName); //<- replaced by the simpler SetWhere form below
                if (File.Exists(Path.Combine(Path.GetDirectoryName(filePath), imageFileName)))
                {
                    imageToUpdate.SetWhere(imageFileName);
                    imagesToUpdate.Add(imageToUpdate);
                    ColumnTuple ColumnTupleFileName = new ColumnTuple(Constant.DatabaseColumn.File, imageFileName);

                    // We have to do the markers later, as we need to get the ID of the matching filename from the data table,
                    // and use that to set the markers.
                    Tuple <string, List <ColumnTuple> > filenameMarkerTuple = new Tuple <string, List <ColumnTuple> >(imageFileName, counterCoordinates);
                    fileNamesMarkersList.Add(filenameMarkerTuple);
                    successCounter++;
                }
                else
                {
                    skippedCounter++;
                }
            }

            // batch update the data table
            imageDatabase.UpdateFiles(imagesToUpdate);

            // Now that we have updated the data table, we can update the markers.
            // We retrieve the ID of the filename associated with the markers from the data table,
            // and use that to set the correct row in the marker table.
            foreach (Tuple <string, List <ColumnTuple> > tuple in fileNamesMarkersList)
            {
                long id = imageDatabase.GetIDFromDataTableByFileName(tuple.Item1);
                ColumnTuplesWithWhere markerToUpdate = new ColumnTuplesWithWhere(tuple.Item2, id);
                markersToUpdate.Add(markerToUpdate);
                imageDatabase.UpdateMarkers(markersToUpdate);
            }

            if (reader != null)
            {
                reader.Dispose();
            }
            return(new Tuple <int, int>(successCounter, skippedCounter));
        }