Files
duplicati/Duplicati/GUI/ApplicationSetup.cs
T
kenneth.skovhede@gmail.com b81d63ea73 Fixed a bug with async uploads that caused some files to no be uploaded.
Fixed a protential race condition with warning messages and file counts (cosmetic only) when using async transfers.
Spelling correction, Seperator -> Separator.
Changed so a restore operation can also supply advanced options.
Changed the format of timestamps in filenames to follow the Duplicity convention, which removes the need for --time-separator and --use-short-filenames.
Moved the URL utility into Core, to avoid compilation errors with Monodevelop.
Reorganized the runner to better support the LiveControls on all operations rather than only for backup/restore.

Update issue #210
Status: Fixed
I have now changed the time format to follow the Duplicity naming convention.
This means that all filenames are now generated with the time set as "yyyyMMddTHHmmssZ".
This format is more portable across all platforms, and easily sortable/readable.
The drawback is that the Z indicates UTC time, so if one looks at the filenames, 
the times are not local. The motivation for this is to avoid trouble
with daylight savings time offsets.

There is full backwards compatibility as long as backups have not used more than
one character for --time-separator (only possible via commandline).
This new format means that the options --time-separator and --use-short-filenames
are now deprecated and removed from the user interface. It is possible to
access them from the advanced options page, along with the --use-old-filenames option.

If anyone needs these options for some reason, let me know, otherwise they will be removed
in a later version.



git-svn-id: https://duplicati.googlecode.com/svn/trunk@523 59da171f-624f-0410-aa54-27559c288bec
2010-09-25 12:02:14 +00:00

525 lines
22 KiB
C#

#region Disclaimer / License
// Copyright (C) 2010, Kenneth Skovhede
// http://www.hexad.dk, opensource@hexad.dk
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
//
#endregion
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Data.LightDatamodel;
using Duplicati.Datamodel;
using System.Globalization;
using Duplicati.Library.Core;
namespace Duplicati.GUI
{
public partial class ApplicationSetup : Form
{
private IDataFetcherWithRelations m_connection;
private ApplicationSettings m_settings;
private bool m_isUpdating = false;
//These variables handle the worker thread size calculation
private object m_lock = new object();
private System.Threading.Thread m_thread = null;
private bool m_restartCalculator = false;
public ApplicationSetup()
{
InitializeComponent();
m_connection = new DataFetcherNested(Program.DataConnection);
m_settings = new ApplicationSettings(m_connection);
RecentDuration.SetIntervals(new List<KeyValuePair<string, string>>(
new KeyValuePair<string, string>[]
{
new KeyValuePair<string, string>(Strings.Common.OneWeek, "1W"),
new KeyValuePair<string, string>(Strings.Common.TwoWeeks, "2W"),
new KeyValuePair<string, string>(Strings.Common.OneMonth, "1M"),
new KeyValuePair<string, string>(Strings.Common.ThreeMonths, "3M"),
}));
StartupDelayDuration.SetIntervals(new List<KeyValuePair<string, string>>(
new KeyValuePair<string, string>[]
{
new KeyValuePair<string, string>(Strings.Common.NoMinutes, "0"),
new KeyValuePair<string, string>(Strings.Common.OneMinute, "1m"),
new KeyValuePair<string, string>(Strings.Common.FiveMinutes, "5m"),
new KeyValuePair<string, string>(Strings.Common.FifteenMinutes, "15m"),
new KeyValuePair<string, string>(Strings.Common.ThirtyMinutes, "30m"),
}));
try
{
LanguageSelection.Items.Clear();
LanguageSelection.Items.Add(new ComboBoxItemPair<CultureInfo>(string.Format(Strings.ApplicationSetup.DefaultLanguage, Library.Core.Utility.DefaultCulture.DisplayName), Library.Core.Utility.DefaultCulture));
System.Text.RegularExpressions.Regex cix = new System.Text.RegularExpressions.Regex("[A-z][A-z](\\-[A-z][A-z])?");
foreach(string f in System.IO.Directory.GetDirectories(Application.StartupPath))
if (cix.Match(System.IO.Path.GetFileName(f)).Length == System.IO.Path.GetFileName(f).Length)
try
{
CultureInfo ci = CultureInfo.GetCultureInfo(System.IO.Path.GetFileName(f));
LanguageSelection.Items.Add(new ComboBoxItemPair<CultureInfo>(ci.DisplayName, ci));
}
catch
{
}
}
finally
{
m_isUpdating = false;
}
try
{
EncryptionModule.Items.Clear();
foreach (Library.Interface.IEncryption e in Library.DynamicLoader.EncryptionLoader.Modules)
EncryptionModule.Items.Add(new ComboBoxItemPair<Library.Interface.IEncryption>(e.DisplayName, e));
}
catch (Exception ex)
{
MessageBox.Show(this, string.Format(Strings.ApplicationSetup.EncryptionModuleLoadError, ex.Message), Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
}
this.Icon = Properties.Resources.TrayNormal;
}
private void RecentDuration_TextChanged(object sender, EventArgs e)
{
if (m_isUpdating)
return;
m_settings.RecentBackupDuration = RecentDuration.Value;
}
private void OKBtn_Click(object sender, EventArgs e)
{
foreach(TabPage tab in TabContainer.TabPages)
if (tab.Tag as Library.Interface.ISettingsControl != null)
{
try
{
if (!(tab.Tag as Library.Interface.ISettingsControl).Validate(tab.Controls[0]))
return;
(tab.Tag as Library.Interface.ISettingsControl).Leave(tab.Controls[0]);
}
catch (Exception ex)
{
MessageBox.Show(this, string.Format(Strings.ApplicationSetup.SaveExtensionError, ex), Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
}
//Commit all changes made to the context
m_connection.CommitAllRecursive();
System.Globalization.CultureInfo newCI = System.Threading.Thread.CurrentThread.CurrentUICulture;
try
{
if (string.IsNullOrEmpty(m_settings.DisplayLanguage))
newCI = Library.Core.Utility.DefaultCulture;
else
newCI = System.Globalization.CultureInfo.GetCultureInfo(m_settings.DisplayLanguage);
}
catch
{
}
if (newCI != System.Threading.Thread.CurrentThread.CurrentUICulture)
{
MessageBox.Show(this, Strings.ApplicationSetup.LanguageChangedWarning, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Information);
//We don't change here, because the application has loaded some
// resources already, so the switch would be partial
}
this.DialogResult = DialogResult.OK;
this.Close();
}
private void RecentDuration_ValueChanged(object sender, EventArgs e)
{
RecentDuration_TextChanged(sender, e);
}
private void TempPathBrowse_Click(object sender, EventArgs e)
{
if (BrowseTempPath.ShowDialog(this) == DialogResult.OK)
TempPath.Text = BrowseTempPath.SelectedPath;
}
private void TempPath_TextChanged(object sender, EventArgs e)
{
if (m_isUpdating)
return;
m_settings.TempPath = TempPath.Text;
}
private void ApplicationSetup_Load(object sender, EventArgs e)
{
try
{
this.Text = string.Format(Strings.ApplicationSetup.DialogTitle, System.Reflection.Assembly.GetExecutingAssembly().GetName().Version);
m_isUpdating = true;
RecentDuration.Value = m_settings.RecentBackupDuration;
TempPath.Text = m_settings.TempPath;
UseCommonPassword.Checked = m_settings.UseCommonPassword;
CommonPassword.Text = m_settings.CommonPassword;
CommonPassword.AskToEnterNewPassword = !string.IsNullOrEmpty(CommonPassword.Text);
if (EncryptionModule.Items.Count > 0)
{
bool foundEncryption = false;
int defaultIndex = 0;
for (int i = 0; i < EncryptionModule.Items.Count; i++)
if (((ComboBoxItemPair<Library.Interface.IEncryption>)EncryptionModule.Items[i]).Value.FilenameExtension == m_settings.CommonPasswordEncryptionModule)
{
foundEncryption = true;
EncryptionModule.SelectedIndex = i;
break;
}
else if (((ComboBoxItemPair<Library.Interface.IEncryption>)EncryptionModule.Items[i]).Value.FilenameExtension == "aes")
defaultIndex = i;
if (!foundEncryption)
EncryptionModule.SelectedIndex = defaultIndex;
}
else
{
PasswordDefaultsGroup.Enabled = false;
}
SignatureCacheEnabled.Checked = m_settings.SignatureCacheEnabled;
SignatureCachePath.Text = m_settings.SignatureCachePath;
CalculateSignatureCacheSize();
StartupDelayDuration.Value = m_settings.StartupDelayDuration;
ThreadPriorityPicker.SelectedPriority = m_settings.ThreadPriorityOverride;
Bandwidth.UploadLimit = m_settings.UploadSpeedLimit;
Bandwidth.DownloadLimit = m_settings.DownloadSpeedLimit;
HideDonateButton.Checked = m_settings.HideDonateButton;
if (string.IsNullOrEmpty(m_settings.DisplayLanguage))
LanguageSelection.SelectedIndex = 0;
else
{
try
{
LanguageSelection.SelectedIndex = -1;
System.Globalization.CultureInfo cci = System.Globalization.CultureInfo.GetCultureInfo(m_settings.DisplayLanguage);
for(int i = 0; i < LanguageSelection.Items.Count; i++)
if (((ComboBoxItemPair<CultureInfo>)LanguageSelection.Items[i]).Value == cci)
{
LanguageSelection.SelectedIndex = i;
break;
}
}
catch
{
LanguageSelection.SelectedIndex = -1;
}
}
try
{
foreach (Library.Interface.ISettingsControl ic in Library.DynamicLoader.SettingsControlLoader.Modules)
{
Control c = ic.GetControl(m_settings.CreateDetachedCopy(), Datamodel.SettingExtension.GetExtensions(m_connection, ic.Key));
c.Dock = DockStyle.Fill;
TabPage tab = new TabPage();
tab.Text = ic.PageTitle;
tab.ToolTipText = ic.PageDescription;
tab.Controls.Add(c);
tab.Tag = ic;
TabContainer.TabPages.Add(tab);
}
}
catch (Exception ex)
{
MessageBox.Show(this, string.Format(Strings.ApplicationSetup.SettingControlsLoadError, ex.Message), Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
}
//Place the license page last
TabContainer.TabPages.Remove(LicenseTab);
TabContainer.TabPages.Insert(TabContainer.TabPages.Count, LicenseTab);
string licensePath = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), "licenses");
List<Duplicati.License.LicenseEntry> licenses = Duplicati.License.LicenseReader.ReadLicenses(licensePath);
licenses.Insert(0, new Duplicati.License.LicenseEntry("Duplicati", System.IO.Path.Combine(licensePath, "duplicati-url.txt"), System.IO.Path.Combine(licensePath, "license.txt")));
licenses.Insert(0, new Duplicati.License.LicenseEntry("Acknowledgements", System.IO.Path.Combine(licensePath, "duplicati-url.txt"), System.IO.Path.Combine(licensePath, "acknowledgements.txt")));
LicenseSections.Items.Clear();
LicenseSections.Items.AddRange(licenses.ToArray());
LicenseSections.SelectedIndex = -1;
LicenseSections.SelectedIndex = 0;
}
finally
{
m_isUpdating = false;
}
}
private void UseCommonPassword_CheckedChanged(object sender, EventArgs e)
{
PasswordPanel.Enabled = UseCommonPassword.Checked;
if (m_isUpdating)
return;
m_settings.UseCommonPassword = UseCommonPassword.Checked;
if (m_settings.UseCommonPassword)
m_settings.CommonPassword = CommonPassword.Text;
else
m_settings.CommonPassword = ""; //Clear it from DB
}
private void CommonPassword_TextChanged(object sender, EventArgs e)
{
if (m_isUpdating)
return;
m_settings.CommonPassword = CommonPassword.Text;
}
private void SignatureCachePathBrowse_Click(object sender, EventArgs e)
{
if (BrowseSignatureCachePath.ShowDialog(this) == DialogResult.OK)
SignatureCachePath.Text = BrowseSignatureCachePath.SelectedPath;
}
private void SignatureCachePath_TextChanged(object sender, EventArgs e)
{
if (m_isUpdating)
return;
m_settings.SignatureCachePath = SignatureCachePath.Text;
CalculateSignatureCacheSize();
}
private void SignatureCacheEnabled_CheckedChanged(object sender, EventArgs e)
{
SignatureCachePath.Enabled = SignatureCachePathBrowse.Enabled = SignatureCacheEnabled.Checked;
if (m_isUpdating)
return;
m_settings.SignatureCacheEnabled = SignatureCacheEnabled.Checked;
CalculateSignatureCacheSize();
}
private void CacheSizeCalculator_DoWork(object sender, DoWorkEventArgs e)
{
lock (m_lock)
m_thread = System.Threading.Thread.CurrentThread;
try
{
e.Result = string.Format(Strings.ApplicationSetup.CacheSize, Library.Core.Utility.FormatSizeString(Library.Core.Utility.GetDirectorySize(System.Environment.ExpandEnvironmentVariables((string)e.Argument), null)));
}
catch (System.Threading.ThreadAbortException)
{
System.Threading.Thread.ResetAbort();
e.Cancel = true;
}
finally
{
lock (m_lock)
m_thread = null;
}
}
private void CacheSizeCalculator_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Cancelled)
CacheSizeLabel.Text = Strings.ApplicationSetup.OperationCancelled;
else if (e.Error != null)
CacheSizeLabel.Text = e.Error.Message;
else
CacheSizeLabel.Text = (string)e.Result;
if (m_restartCalculator)
CalculateSignatureCacheSize();
}
private void CalculateSignatureCacheSize()
{
CacheSizeLabel.Text = Strings.ApplicationSetup.CalculatingCacheSize;
lock (m_lock)
if (CacheSizeCalculator.IsBusy)
{
m_restartCalculator = true;
m_thread.Abort();
}
else
{
m_restartCalculator = false;
if (SignatureCacheEnabled.Checked)
CacheSizeCalculator.RunWorkerAsync(SignatureCachePath.Text);
else
CacheSizeLabel.Text = "";
}
}
private void ClearCacheButton_Click(object sender, EventArgs e)
{
try
{
string path = System.Environment.ExpandEnvironmentVariables(SignatureCachePath.Text);
if (MessageBox.Show(this, string.Format(Strings.ApplicationSetup.ConfirmCacheDelete, path), Application.ProductName, MessageBoxButtons.YesNoCancel, MessageBoxIcon.Warning) != DialogResult.Yes)
return;
Library.Main.Interface.RemoveSignatureFiles(path);
CalculateSignatureCacheSize();
}
catch(Exception ex)
{
MessageBox.Show(this, string.Format(Strings.Common.GenericError, ex.Message), Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void ApplicationSetup_FormClosing(object sender, FormClosingEventArgs e)
{
lock(m_lock)
if (m_thread != null)
{
m_restartCalculator = false;
m_thread.Abort();
}
}
private void LanguageSelection_SelectedIndexChanged(object sender, EventArgs e)
{
if (m_isUpdating)
return;
if (LanguageSelection.SelectedIndex == 0)
m_settings.DisplayLanguage = "";
else if (LanguageSelection.SelectedIndex > 0)
m_settings.DisplayLanguage = ((ComboBoxItemPair<CultureInfo>)LanguageSelection.SelectedItem).Value.Name;
}
private void StartupDelayDuration_ValueChanged(object sender, EventArgs e)
{
if (m_isUpdating)
return;
m_settings.StartupDelayDuration = StartupDelayDuration.Value;
}
private void ThreadPriorityPicker_SelectedPriorityChanged(object sender, EventArgs e)
{
if (m_isUpdating)
return;
m_settings.ThreadPriorityOverride = ThreadPriorityPicker.SelectedPriority;
}
private void Bandwidth_UploadLimitChanged(object sender, EventArgs e)
{
if (m_isUpdating)
return;
m_settings.UploadSpeedLimit = Bandwidth.UploadLimit;
}
private void Bandwidth_DownloadLimitChanged(object sender, EventArgs e)
{
if (m_isUpdating)
return;
m_settings.DownloadSpeedLimit = Bandwidth.DownloadLimit;
}
private void EncryptionModule_SelectedIndexChanged(object sender, EventArgs e)
{
if (m_isUpdating)
return;
if (EncryptionModule.SelectedItem as ComboBoxItemPair<Library.Interface.IEncryption> != null)
m_settings.CommonPasswordEncryptionModule = ((ComboBoxItemPair<Library.Interface.IEncryption>)EncryptionModule.SelectedItem).Value.FilenameExtension;
}
public static Dictionary<string, string> GetApplicationSettings(IDataFetcher connection)
{
Dictionary<string, string> env = new ApplicationSettings(connection).CreateDetachedCopy();
//If there are any control extensions, let them modify the environement
foreach (Library.Interface.ISettingsControl ic in Library.DynamicLoader.SettingsControlLoader.Modules)
ic.BeginEdit(env, SettingExtension.GetExtensions(connection, ic.Key));
return env;
}
public static void SaveExtensionSettings(IDataFetcher connection, IDictionary<string, string> env)
{
//If there are any control extensions, let them modify the environement
foreach (Library.Interface.ISettingsControl ic in Library.DynamicLoader.SettingsControlLoader.Modules)
ic.EndEdit(env, SettingExtension.GetExtensions(connection, ic.Key));
}
private void HideDonateButton_CheckedChanged(object sender, EventArgs e)
{
if (m_isUpdating)
return;
m_settings.HideDonateButton = HideDonateButton.Checked;
}
private void LicenseSections_SelectedIndexChanged(object sender, EventArgs e)
{
if (LicenseSections.SelectedItem as Duplicati.License.LicenseEntry != null)
{
Duplicati.License.LicenseEntry l = LicenseSections.SelectedItem as Duplicati.License.LicenseEntry;
LicenseText.Text = l.License;
LicenseLink.Visible = !string.IsNullOrEmpty(l.Url);
}
}
private void LicenseLink_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
if (LicenseSections.SelectedItem as Duplicati.License.LicenseEntry != null)
{
Duplicati.License.LicenseEntry l = LicenseSections.SelectedItem as Duplicati.License.LicenseEntry;
if (!string.IsNullOrEmpty(l.Url))
Duplicati.Library.Core.UrlUtillity.OpenUrl(l.Url);
}
}
}
}