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;
            }
        }
Пример #2
0
        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;
        }
Пример #3
0
        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);
            }
        }
Пример #4
0
        // 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);
        }