private void CheckForUpdateButton_Click(object sender, RoutedEventArgs e) { VersionChecks updater = new VersionChecks(this, Constant.VersionUpdates.ApplicationName, Constant.VersionUpdates.LatestVersionFileNameXML); if (updater.TryCheckForNewVersionAndDisplayResultsAsNeeded(true)) { // PERHAPS. This isn't quite right, as the most recent check for update data is (I think) set only if there is a new release // (as true is only returned by TryGetAndParseVersion when that happens, I think). // Maybe the most recent check date should be done anytime a check is done??? this.MostRecentCheckForUpdate = DateTime.UtcNow; } }
private void Window_Loaded(object sender, RoutedEventArgs e) { // Abort if some of the required dependencies are missing if (Dependencies.AreRequiredBinariesPresent(Constant.VersionUpdates.ApplicationName, Assembly.GetExecutingAssembly()) == false) { Dialogs.DependencyFilesMissingDialog(Constant.VersionUpdates.ApplicationName); Application.Current.Shutdown(); } // Check for updates at least once a day if (DateTime.Now.Year != this.State.MostRecentCheckForUpdates.Year || DateTime.Now.Month != this.State.MostRecentCheckForUpdates.Month || DateTime.Now.Day != this.State.MostRecentCheckForUpdates.Day) { VersionChecks updater = new VersionChecks(this, Constant.VersionUpdates.ApplicationName, Constant.VersionUpdates.LatestVersionFileNameXML); updater.TryCheckForNewVersionAndDisplayResultsAsNeeded(false); this.State.MostRecentCheckForUpdates = DateTime.UtcNow; } if (this.State.FirstTimeFileLoading) { // Load the previously saved layout. If there is none, TryLoad will default to a reasonable layout and window size/position. this.AvalonLayout_TryLoad(Constant.AvalonLayoutTags.LastUsed); this.State.FirstTimeFileLoading = false; } if (!SystemStatus.CheckAndGetLangaugeAndCulture(out _, out _, out string displayname)) { this.HelpDocument.WarningRegionLanguage = displayname; } // Add a context menu to the data controls that allows a user to restore default values to the current or selected file // I originally had this in the XAML, but for some reason it complains if put there. ContextMenu menuRestoreDefaults = new ContextMenu(); //{ // Name = "MenuRestoreDefaults" //}; MenuItem menuItemRestoreDefaults = new MenuItem(); //{ // Header = "Restore default values for this file", // ToolTip = "Restores the default values for all fields for this file excepting file paths and date/times" //}; menuItemRestoreDefaults.Click += MenuItemRestoreDefaultValues_Click; menuRestoreDefaults.Opened += this.MenuRestoreDefaults_Opened; menuRestoreDefaults.Items.Add(menuItemRestoreDefaults); this.DataEntryControls.ContextMenu = menuRestoreDefaults; this.DataEntryControlPanel.IsVisible = false; this.InstructionPane.IsActive = true; }
private async void Window_Loaded(object sender, RoutedEventArgs e) { // Abort if some of the required dependencies are missing if (Dependencies.AreRequiredBinariesPresent(Constant.VersionUpdates.ApplicationName, Assembly.GetExecutingAssembly()) == false) { Dialogs.DependencyFilesMissingDialog(Constant.VersionUpdates.ApplicationName); Application.Current.Shutdown(); } // Check for updates at least once a day if (DateTime.Now.Year != this.State.MostRecentCheckForUpdates.Year || DateTime.Now.Month != this.State.MostRecentCheckForUpdates.Month || DateTime.Now.Day != this.State.MostRecentCheckForUpdates.Day) { VersionChecks updater = new VersionChecks(this, Constant.VersionUpdates.ApplicationName, Constant.VersionUpdates.LatestVersionFileNameXML); updater.TryCheckForNewVersionAndDisplayResultsAsNeeded(false); this.State.MostRecentCheckForUpdates = DateTime.Now; } if (this.State.FirstTimeFileLoading) { // Load the previously saved layout. If there is none, TryLoad will default to a reasonable layout and window size/position. this.AvalonLayout_TryLoad(Constant.AvalonLayoutTags.LastUsed); this.State.FirstTimeFileLoading = false; } if (!SystemStatus.CheckAndGetLangaugeAndCulture(out _, out _, out string displayname)) { this.HelpDocument.WarningRegionLanguage = displayname; } // Add a context menu to the data controls that allows a user to restore default values to the current or selected file // I originally had this in the XAML, but for some reason it complains if put there. ContextMenu menuRestoreDefaults = new ContextMenu(); //{ // Name = "MenuRestoreDefaults" //}; MenuItem menuItemRestoreDefaults = new MenuItem(); //{ // Header = "Restore default values for this file", // ToolTip = "Restores the default values for all fields for this file excepting file paths and date/times" //}; menuItemRestoreDefaults.Click += MenuItemRestoreDefaultValues_Click; menuRestoreDefaults.Opened += this.MenuRestoreDefaults_Opened; menuRestoreDefaults.Items.Add(menuItemRestoreDefaults); this.DataEntryControls.ContextMenu = menuRestoreDefaults; if (this.Arguments.IsViewOnly) { this.State.IsViewOnly = true; // Because its readonly, disable the data entry panel, the copy previous values button, the data entry panels' context menu etc. // Individual controls are disabled in the DataEntryX panel this.DataEntryControls.ContextMenu = null; this.CopyPreviousValuesButton.Visibility = Visibility.Collapsed; this.EnableOrDisableMenusAndControls(); } this.DataEntryControlPanel.IsVisible = false; this.InstructionPane.IsActive = true; if (false == String.IsNullOrEmpty(this.Arguments.Template)) { if (File.Exists(this.Arguments.Template)) { Mouse.OverrideCursor = Cursors.Wait; this.StatusBar.SetMessage("Loading images, please wait..."); await this.TryOpenTemplateAndBeginLoadFoldersAsync(this.Arguments.Template).ConfigureAwait(true); if (false == String.IsNullOrEmpty(this.Arguments.RelativePath)) { // Set and only use the relative path as a search term this.DataHandler.FileDatabase.CustomSelection.ClearCustomSearchUses(); this.DataHandler.FileDatabase.CustomSelection.SetAndUseRelativePathSearchTerm(this.Arguments.RelativePath); if (null == this.DataHandler?.ImageCache?.Current) { await this.FilesSelectAndShowAsync(FileSelectionEnum.Folders).ConfigureAwait(true); // Go to the first result (i.e., index 0) in the given selection set } else { await this.FilesSelectAndShowAsync(this.DataHandler.ImageCache.Current.ID, FileSelectionEnum.Folders).ConfigureAwait(true); // Go to the first result (i.e., index 0) in the given selection set } } this.StatusBar.SetMessage("Image set is now loaded."); Mouse.OverrideCursor = null; if (this.Arguments.ConstrainToRelativePath) { // Tell user that its a constrained relative path, // Also, set the File menus so that users cannot close and reopen a new image set // This is to avoid confusion as to how the user may mis-interpret the argument state given another image set Dialogs.ArgumentRelativePathDialog(this, this.Arguments.RelativePath); this.MenuItemExit.Header = "Close image set and exit Timelapse"; this.MenuFileCloseImageSet.Visibility = Visibility.Collapsed; } } else { // We can't open the template. Show a message and ignore the arguments (by clearing them) Dialogs.ArgumentTemplatePathDialog(this, this.Arguments.Template, this.Arguments.RelativePath); this.Arguments = new DataStructures.Arguments(null); } } if (this.State.IsViewOnly) { Dialog.Dialogs.OpeningMessageReadOnly(this); } if (this.State.SuppressOpeningMessageDialog == false) { Dialogs.OpeningMessage(this); } }
// Load the specified database template and then the associated images. // templateDatabasePath is the Fully qualified path to the template database file. // Returns true only if both the template and image database file are loaded (regardless of whether any images were loaded) , false otherwise private async Task <bool> TryOpenTemplateAndBeginLoadFoldersAsync(string templateDatabasePath) { // Try to create or open the template database // First, check the file path length and notify the user the template couldn't be loaded because its path is too long if (IsCondition.IsPathLengthTooLong(templateDatabasePath)) { Mouse.OverrideCursor = null; Dialogs.TemplatePathTooLongDialog(this, templateDatabasePath); return(false); } // Second, check to see if we can actually open it. // As we can't have out parameters in an async method, we return the state and the desired templateDatabase as a tuple Tuple <bool, TemplateDatabase> tupleResult = await TemplateDatabase.TryCreateOrOpenAsync(templateDatabasePath).ConfigureAwait(true); this.templateDatabase = tupleResult.Item2; if (!tupleResult.Item1) { // Notify the user the template couldn't be loaded rather than silently doing nothing Mouse.OverrideCursor = null; Dialogs.TemplateFileNotLoadedAsCorruptDialog(this, templateDatabasePath); return(false); } // The .tdb templateDatabase should now be loaded // Try to get the image database file path // importImages will be true if its a new image database file, (meaning we should later ask the user to try to import some images) if (this.TrySelectDatabaseFile(templateDatabasePath, out string fileDatabaseFilePath, out bool importImages) == false) { // No image database file was selected return(false); } // Check the file path length of the .ddb file and notify the user the ddb couldn't be loaded because its path is too long if (IsCondition.IsPathLengthTooLong(fileDatabaseFilePath)) { Mouse.OverrideCursor = null; Dialogs.DatabasePathTooLongDialog(this, fileDatabaseFilePath); return(false); } // Check the expected file path length of the backup files, and warn the user if backups may not be made because thier path is too long if (IsCondition.IsBackupPathLengthTooLong(templateDatabasePath) || IsCondition.IsBackupPathLengthTooLong(fileDatabaseFilePath)) { Mouse.OverrideCursor = null; Dialogs.BackupPathTooLongDialog(this); } // Before fully loading an existing image database, // - upgrade the template tables if needed for backwards compatability (done automatically) // - compare the controls in the .tdb and .ddb template tables to see if there are any added or missing controls TemplateSyncResults templateSyncResults = new Database.TemplateSyncResults(); bool backUpJustMade = false; using (FileDatabase fileDB = await FileDatabase.UpgradeDatabasesAndCompareTemplates(fileDatabaseFilePath, this.templateDatabase, templateSyncResults).ConfigureAwait(true)) { // A file database was available to open if (fileDB != null) { if (templateSyncResults.ControlSynchronizationErrors.Count > 0 || (templateSyncResults.ControlSynchronizationWarnings.Count > 0 && templateSyncResults.SyncRequiredAsDataLabelsDiffer == false)) { // There are unresolvable syncronization issues. Report them now as we cannot use this template. // Depending on the user response, we either abort Timelapse or use the template found in the ddb file Mouse.OverrideCursor = null; Dialog.TemplateSynchronization templatesNotCompatibleDialog; templatesNotCompatibleDialog = new Dialog.TemplateSynchronization(templateSyncResults.ControlSynchronizationErrors, templateSyncResults.ControlSynchronizationWarnings, this); bool?result = templatesNotCompatibleDialog.ShowDialog(); if (result == false) { // user indicates exiting rather than continuing. Application.Current.Shutdown(); return(false); } else { templateSyncResults.UseTemplateDBTemplate = templatesNotCompatibleDialog.UseNewTemplate; templateSyncResults.SyncRequiredAsChoiceMenusDiffer = templateSyncResults.ControlSynchronizationWarnings.Count > 0; } } else if (templateSyncResults.SyncRequiredAsDataLabelsDiffer) { // If there are any new or missing columns, report them now // Depending on the user response, set the useTemplateDBTemplate to signal whether we should: // - update the template and image data columns in the image database // - use the old template Mouse.OverrideCursor = null; TemplateChangedAndUpdate templateChangedAndUpdate = new TemplateChangedAndUpdate(templateSyncResults, this); bool?result1 = templateChangedAndUpdate.ShowDialog(); templateSyncResults.UseTemplateDBTemplate = result1 == true; } else if (templateSyncResults.SyncRequiredAsNonCriticalFieldsDiffer) { // Non critical differences in template, so these don't need reporting templateSyncResults.UseTemplateDBTemplate = true; } backUpJustMade = fileDB.mostRecentBackup != DateTime.MinValue; } else if (File.Exists(fileDatabaseFilePath) == true) { // The .ddb file (which exists) is for some reason unreadable. // It is likely due to an empty or corrupt or otherwise unreadable database in the file. // Raise an error message bool isEmpty = File.Exists(fileDatabaseFilePath) && new FileInfo(fileDatabaseFilePath).Length == 0; Mouse.OverrideCursor = null; Dialogs.DatabaseFileNotLoadedAsCorruptDialog(this, fileDatabaseFilePath, isEmpty); return(false); } ; } // At this point: // - for backwards compatability, all old databases will have been updated (if needed) to the current version standard // - we should have a valid template and image database loaded // - we know if the user wants to use the old or the new template // So lets load the database for real. The useTemplateDBTemplate signals whether to use the template stored in the DDB, or to use the TDB template. FileDatabase fileDatabase = await FileDatabase.CreateOrOpenAsync(fileDatabaseFilePath, this.templateDatabase, this.State.CustomSelectionTermCombiningOperator, templateSyncResults, backUpJustMade).ConfigureAwait(true); // The next test is to test and syncronize (if needed) the default values stored in the fileDB table schema to those stored in the template Dictionary <string, string> columndefaultdict = fileDatabase.SchemaGetColumnsAndDefaultValues(Constant.DBTables.FileData); char[] quote = { '\'' }; foreach (KeyValuePair <string, string> pair in columndefaultdict) { ControlRow row = this.templateDatabase.GetControlFromTemplateTable(pair.Key); if (row != null && pair.Value.Trim(quote) != row.DefaultValue) { // If even one default is different between the schema default and the template default, update the entire file table. fileDatabase.UpgradeFileDBSchemaDefaultsFromTemplate(); break; } } // Check to see if the root folder stored in the database is the same as the actual root folder. If not, ask the user if it should be changed. this.CheckAndCorrectRootFolder(fileDatabase); // Check to see if there are any missing folders as specified by the relative paths. For those missing, ask the user to try to locate those folders. int missingFoldersCount = TimelapseWindow.GetMissingFolders(fileDatabase).Count; if (missingFoldersCount > 0) { Dialogs.MissingFoldersInformationDialog(this, missingFoldersCount); } // Generate and render the data entry controls, regardless of whether there are actually any files in the files database. this.DataHandler = new DataEntryHandler(fileDatabase); this.DataEntryControls.CreateControls(fileDatabase, this.DataHandler); this.SetUserInterfaceCallbacks(); this.MarkableCanvas.DataEntryControls = this.DataEntryControls; // so the markable canvas can access the controls this.DataHandler.ThumbnailGrid = this.MarkableCanvas.ThumbnailGrid; this.DataHandler.MarkableCanvas = this.MarkableCanvas; this.Title = Constant.Defaults.MainWindowBaseTitle + " (" + Path.GetFileName(fileDatabase.FilePath) + ")"; this.State.MostRecentImageSets.SetMostRecent(templateDatabasePath); this.RecentFileSets_Refresh(); // Record the version number of the currently executing version of Timelapse only if its greater than the one already stored in the ImageSet Table. // This will indicate the latest timelapse version that is compatable with the database structure. string currentVersionNumberAsString = VersionChecks.GetTimelapseCurrentVersionNumber().ToString(); if (VersionChecks.IsVersion1GreaterThanVersion2(currentVersionNumberAsString, this.DataHandler.FileDatabase.ImageSet.VersionCompatability)) { this.DataHandler.FileDatabase.ImageSet.VersionCompatability = currentVersionNumberAsString; this.DataHandler.FileDatabase.UpdateSyncImageSetToDatabase(); } // Create an index on RelativePath, File,and RelativePath/File if it doesn't already exist // This is really just a version check in case old databases don't have the index created, // Newer databases (from 2.2.4.4 onwards) will have these indexes created and updated whenever images are loaded or added for the first time. // If the index exists, this is a very cheap operation so there really is no need to do it by a version number check. this.DataHandler.FileDatabase.IndexCreateForFileAndRelativePathIfNotExists(); // If this is a new image database, try to load images (if any) from the folder... if (importImages) { this.TryBeginImageFolderLoad(this.FolderPath, this.FolderPath); } else { await this.OnFolderLoadingCompleteAsync(false).ConfigureAwait(true); } return(true); }