/// <summary> /// Adds a column with the given column name and value pair. /// </summary> /// <param name="columnName"></param> /// <param name="columnValue"></param> protected void AddColumn(string columnName, decimal?columnValue) { ColumnTuple columnTuple = new ColumnTuple(); columnTuple.Name = columnName; columnTuple.ValueType = typeof(decimal?); columnTuple.Value = columnValue; RegisteredColumns.Add(columnTuple); }
/// <summary> /// Adds a column with the given column name and value pair. /// </summary> /// <param name="columnName"></param> /// <param name="columnValue"></param> protected void AddColumn(string columnName, SqlBoolean columnValue) { ColumnTuple columnTuple = new ColumnTuple(); columnTuple.Name = columnName; columnTuple.ValueType = typeof(SqlBoolean); columnTuple.Value = columnValue; RegisteredColumns.Add(columnTuple); }
/// <summary> /// If there are missing folders, search for possible matches and raise a dialog box asking the user to locate them /// </summary> /// <param name="owner"></param> /// <param name="fileDatabase"></param> /// <param name="missingFolders"></param> /// <returns>whether any folder are actually missing </returns> private static bool?CorrectForMissingFolders(Window owner, FileDatabase fileDatabase, List <string> missingRelativePaths) { // Abort if the arguments for null if (null == fileDatabase) { return(null); } if (null == missingRelativePaths) { return(null); } // We know that at least one or more folders are missing. // For each missing folder path, try to find all folders with the same name under the root folder. Dictionary <string, List <string> > matchingFolderNames = Util.FilesFolders.TryGetMissingFolders(fileDatabase.FolderPath, missingRelativePaths); Dictionary <string, string> finalFileLocations; // We want to show the normal cursor when we display dialog boxes, so save the current cursor so we can store it. Cursor cursor = Mouse.OverrideCursor; bool?result; if (matchingFolderNames != null) { Mouse.OverrideCursor = null; // Present a dialog box that asks the user to locate the missing folders. It will show possible locations for each folder (if any). // The user can then confirm correct locations, manually set the locaton of those folders, or cancel altogether. MissingFoldersLocateAllFolders dialog = new MissingFoldersLocateAllFolders(owner, fileDatabase.FolderPath, matchingFolderNames); result = dialog.ShowDialog(); if (result == true) { // Get the updated folder locations and update the database finalFileLocations = dialog.FinalFolderLocations; foreach (string key in finalFileLocations.Keys) { ColumnTuple columnToUpdate = new ColumnTuple(Constant.DatabaseColumn.RelativePath, finalFileLocations[key]); ColumnTuplesWithWhere columnToUpdateWithWhere = new ColumnTuplesWithWhere(columnToUpdate, key); fileDatabase.UpdateFiles(columnToUpdateWithWhere); } Mouse.OverrideCursor = cursor; return(true); } } Mouse.OverrideCursor = cursor; return(null); // Operaton aborted }
// Get the root folder name from the database, and check to see if its the same as the actual root folder. // If not, ask the user if he/she wants to update the database. private void CheckAndCorrectRootFolder(FileDatabase fileDatabase) { // Check the arguments for null if (fileDatabase == null) { // this should not happen // System.Diagnostics.Debug.Print("The fielDatabase was null and it shouldn't be"); TracePrint.PrintStackTrace(1); // No-op return; } List <object> allRootFolderPaths = fileDatabase.GetDistinctValuesInColumn(Constant.DBTables.FileData, Constant.DatabaseColumn.Folder); if (allRootFolderPaths.Count < 1) { // System.Diagnostics.Debug.Print("Checking the root folder name in the database, but no entries were found. Perhaps the database is empty?"); return; } // retrieve and compare the db and actual root folder path names. While there really should be only one entry in the allRootFolderPaths, // we still do a check in case there is more than one. If even one entry doesn't match, we use that entry to ask the user if he/she // wants to update the root folder to match the actual location of the root folder containing the template, data and image files. string actualRootFolderName = fileDatabase.FolderPath.Split(Path.DirectorySeparatorChar).Last(); foreach (string databaseRootFolderName in allRootFolderPaths) { if (databaseRootFolderName.Equals(actualRootFolderName)) { continue; } else { // We have at least one entry where there is a mismatch between the actual root folder and the stored root folder // Consequently, ask the user if he/she wants to update the db entry Dialog.UpdateRootFolder renameRootFolderDialog; renameRootFolderDialog = new Dialog.UpdateRootFolder(this, databaseRootFolderName, actualRootFolderName); bool?result = renameRootFolderDialog.ShowDialog(); if (result == true) { ColumnTuple columnToUpdate = new ColumnTuple(Constant.DatabaseColumn.Folder, actualRootFolderName); fileDatabase.UpdateFiles(columnToUpdate); } return; } } }
// 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)); }