Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
234 changes: 234 additions & 0 deletions Scrupdate/Classes/Utilities/ConfigurationImportExportUtilities.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
// Copyright © 2021-2025 Matan Brightbert
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.




using System;
using System.IO;
using System.IO.Compression;
using System.Text;


namespace Scrupdate.Classes.Utilities
{
public static class ConfigurationImportExportUtilities
{
// Constants ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public const string CONFIGURATION_FILE_EXTENSION = ".scrupdate";
public const string CONFIGURATION_FILE_FILTER = "Scrupdate Configuration Files (*.scrupdate)|*.scrupdate";
private const string ENTRY_NAME__SETTINGS = "Settings.json";
private const string ENTRY_NAME__SETTINGS_CHECKSUM = "Settings.json.md5";
private const string ENTRY_NAME__PROGRAM_DATABASE = "Programs.sqlite";
private const string ENTRY_NAME__PROGRAM_DATABASE_CHECKSUM = "Programs.sqlite.md5";
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////



// Methods /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public static bool ExportConfiguration(string exportFilePath)
{
if (exportFilePath == null)
throw new ArgumentNullException(nameof(exportFilePath));
try
{
string exportFileDirectoryPath = Path.GetDirectoryName(exportFilePath);
if (!Directory.Exists(exportFileDirectoryPath))
Directory.CreateDirectory(exportFileDirectoryPath);
using (FileStream fileStream = new FileStream(
exportFilePath,
FileMode.Create,
FileAccess.Write,
FileShare.None
))
{
using (ZipArchive zipArchive = new ZipArchive(fileStream, ZipArchiveMode.Create))
{
if (File.Exists(ApplicationUtilities.settingsFilePath))
{
AddFileToZipArchive(
zipArchive,
ApplicationUtilities.settingsFilePath,
ENTRY_NAME__SETTINGS
);
}
if (File.Exists(ApplicationUtilities.settingsChecksumFilePath))
{
AddFileToZipArchive(
zipArchive,
ApplicationUtilities.settingsChecksumFilePath,
ENTRY_NAME__SETTINGS_CHECKSUM
);
}
if (File.Exists(ApplicationUtilities.programDatabaseFilePath))
{
AddFileToZipArchive(
zipArchive,
ApplicationUtilities.programDatabaseFilePath,
ENTRY_NAME__PROGRAM_DATABASE
);
}
if (File.Exists(ApplicationUtilities.programDatabaseChecksumFilePath))
{
AddFileToZipArchive(
zipArchive,
ApplicationUtilities.programDatabaseChecksumFilePath,
ENTRY_NAME__PROGRAM_DATABASE_CHECKSUM
);
}
}
}
return true;
}
catch
{
try
{
if (File.Exists(exportFilePath))
File.Delete(exportFilePath);
}
catch { }
return false;
}
}
public static bool ImportConfiguration(string importFilePath)
{
if (importFilePath == null)
throw new ArgumentNullException(nameof(importFilePath));
try
{
if (!File.Exists(importFilePath))
return false;
using (FileStream fileStream = new FileStream(
importFilePath,
FileMode.Open,
FileAccess.Read,
FileShare.Read
))
{
using (ZipArchive zipArchive = new ZipArchive(fileStream, ZipArchiveMode.Read))
{
bool hasSettings = (zipArchive.GetEntry(ENTRY_NAME__SETTINGS) != null);
bool hasSettingsChecksum = (zipArchive.GetEntry(ENTRY_NAME__SETTINGS_CHECKSUM) != null);
if (hasSettings != hasSettingsChecksum)
return false;
bool hasProgramDatabase = (zipArchive.GetEntry(ENTRY_NAME__PROGRAM_DATABASE) != null);
bool hasProgramDatabaseChecksum = (zipArchive.GetEntry(ENTRY_NAME__PROGRAM_DATABASE_CHECKSUM) != null);
if (hasProgramDatabase != hasProgramDatabaseChecksum)
return false;
if (!hasSettings && !hasProgramDatabase)
return false;
ApplicationUtilities.CreateDataFolderIfNotExists();
if (hasSettings)
{
ExtractFileFromZipArchive(
zipArchive,
ENTRY_NAME__SETTINGS,
ApplicationUtilities.settingsFilePath
);
ExtractFileFromZipArchive(
zipArchive,
ENTRY_NAME__SETTINGS_CHECKSUM,
ApplicationUtilities.settingsChecksumFilePath
);
try
{
File.SetAttributes(
ApplicationUtilities.settingsChecksumFilePath,
File.GetAttributes(ApplicationUtilities.settingsChecksumFilePath) | FileAttributes.Hidden
);
}
catch { }
}
if (hasProgramDatabase)
{
ExtractFileFromZipArchive(
zipArchive,
ENTRY_NAME__PROGRAM_DATABASE,
ApplicationUtilities.programDatabaseFilePath
);
ExtractFileFromZipArchive(
zipArchive,
ENTRY_NAME__PROGRAM_DATABASE_CHECKSUM,
ApplicationUtilities.programDatabaseChecksumFilePath
);
try
{
File.SetAttributes(
ApplicationUtilities.programDatabaseChecksumFilePath,
File.GetAttributes(ApplicationUtilities.programDatabaseChecksumFilePath) | FileAttributes.Hidden
);
}
catch { }
}
}
}
return true;
}
catch
{
return false;
}
}
private static void AddFileToZipArchive(ZipArchive zipArchive, string sourceFilePath, string entryName)
{
ZipArchiveEntry entry = zipArchive.CreateEntry(entryName, CompressionLevel.Optimal);
using (Stream entryStream = entry.Open())
{
using (FileStream sourceFileStream = new FileStream(
sourceFilePath,
FileMode.Open,
FileAccess.Read,
FileShare.ReadWrite
))
{
sourceFileStream.CopyTo(entryStream);
}
}
}
private static void ExtractFileFromZipArchive(ZipArchive zipArchive, string entryName, string destinationFilePath)
{
ZipArchiveEntry entry = zipArchive.GetEntry(entryName);
if (entry == null)
return;
string destinationDirectoryPath = Path.GetDirectoryName(destinationFilePath);
if (!Directory.Exists(destinationDirectoryPath))
Directory.CreateDirectory(destinationDirectoryPath);
if (File.Exists(destinationFilePath))
{
try
{
File.SetAttributes(
destinationFilePath,
File.GetAttributes(destinationFilePath) & ~FileAttributes.Hidden & ~FileAttributes.ReadOnly
);
}
catch { }
}
using (Stream entryStream = entry.Open())
{
using (FileStream destinationFileStream = new FileStream(
destinationFilePath,
FileMode.Create,
FileAccess.Write,
FileShare.None
))
{
entryStream.CopyTo(destinationFileStream);
}
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
}
}
45 changes: 41 additions & 4 deletions Scrupdate/UiElements/Windows/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright © 2021-2025 Matan Brightbert
// Copyright © 2021-2025 Matan Brightbert
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -46,6 +46,8 @@ public partial class MainWindow : Window, INotifyPropertyChanged
private const string ERROR_DIALOG_MESSAGE__PROGRAM_DATABASE_RECREATION_WAS_FAILED = "Program Database Recreation Was Failed!\r\n\r\n• If this error persists, try to restart your computer or reinstall Scrupdate.";
private const string ERROR_DIALOG_MESSAGE__FAILED_TO_RESET_ONE_OR_MORE_COMPONENTS = "Failed to Reset One or More Components!";
private const string ERROR_DIALOG_MESSAGE__FAILED_TO_SAVE_SETTINGS = "Failed to Save Settings!";
private const string ERROR_DIALOG_MESSAGE__AN_ERROR_HAS_OCCURRED_WHILE_IMPORTING_CONFIGURATION = "An error has occurred while importing the configuration!\r\n\r\n• The selected file may be invalid or corrupted.";
private const string INFORMATION_DIALOG_MESSAGE__CONFIGURATION_HAS_BEEN_IMPORTED_SUCCESSFULLY = "The configuration has been imported successfully!\r\n\r\n• Scrupdate will now close.\r\n• Please reopen Scrupdate to load the imported configuration.";
private const string QUESTION_DIALOG_MESSAGE__ARE_YOU_SURE_YOU_WANT_TO_CLOSE_SCRUPDATE_FORCEFULLY = "Are You Sure You Want to Close Scrupdate Forcefully?\r\n\r\n• If you close Scrupdate forcefully, ChromeDriver will not have a chance to delete its temporary files.";
private const string QUESTION_DIALOG_MESSAGE__DO_YOU_WANT_TO_RECREATE_THE_PROGRAM_DATABASE = "Do You Want to Recreate the Program Database?\r\n\r\n• All the program information and configurations will be lost.";
private const string QUESTION_DIALOG_MESSAGE__REMOVE_THE_SELECTED_PROGRAMS_FROM_THE_LIST = "Remove the Selected Program(s) from the List?";
Expand Down Expand Up @@ -445,9 +447,38 @@ private void OnButtonClickEvent(object sender, RoutedEventArgs e)
else if (senderButton == button_settings)
{
Settings updatedSettings;
if (OpenSettingsWindowAsDialog(out updatedSettings) == true)
bool hasImportedConfiguration;
string importConfigurationFilePath;
if (OpenSettingsWindowAsDialog(out updatedSettings, out hasImportedConfiguration, out importConfigurationFilePath) == true)
{
if (updatedSettings != null)
if (hasImportedConfiguration)
{
resettingAllSettingsAndData = true;
programDatabase?.Close();
if (App.SettingsHandler != null)
{
App.SettingsHandler.Dispose();
App.SettingsHandler = null;
}
if (ConfigurationImportExportUtilities.ImportConfiguration(importConfigurationFilePath))
{
DialogUtilities.ShowInformationDialog(
"",
INFORMATION_DIALOG_MESSAGE__CONFIGURATION_HAS_BEEN_IMPORTED_SUCCESSFULLY,
this
);
}
else
{
DialogUtilities.ShowErrorDialog(
"",
ERROR_DIALOG_MESSAGE__AN_ERROR_HAS_OCCURRED_WHILE_IMPORTING_CONFIGURATION,
this
);
}
Application.Current.Shutdown();
}
else if (updatedSettings != null)
ApplyUpdatedSettings(updatedSettings);
else
{
Expand Down Expand Up @@ -873,9 +904,11 @@ private void OnGridViewColumnsCollectionCollectionChangedEvent(object sender, No


// Methods /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
private bool? OpenSettingsWindowAsDialog(out Settings updatedSettings)
private bool? OpenSettingsWindowAsDialog(out Settings updatedSettings, out bool hasImportedConfiguration, out string importConfigurationFilePath)
{
updatedSettings = null;
hasImportedConfiguration = false;
importConfigurationFilePath = null;
bool? returnValue = null;
SettingsWindow settingsWindow = null;
ThreadingUtilities.RunOnAnotherThread(
Expand All @@ -891,7 +924,11 @@ private void OnGridViewColumnsCollectionCollectionChangedEvent(object sender, No
}
);
if (returnValue == true)
{
updatedSettings = settingsWindow.GetUpdatedSettings();
hasImportedConfiguration = settingsWindow.HasImportedConfiguration();
importConfigurationFilePath = settingsWindow.GetImportConfigurationFilePath();
}
return returnValue;
}
private void OpenUserManualFile()
Expand Down
Loading