diff --git a/Duplicati/DuplicityRunner.cs b/Duplicati/DuplicityRunner.cs index 70ef005af..71eee9572 100644 --- a/Duplicati/DuplicityRunner.cs +++ b/Duplicati/DuplicityRunner.cs @@ -64,41 +64,44 @@ namespace Duplicati env["PATH"] = System.Environment.ExpandEnvironmentVariables(Program.ApplicationSettings.PGPPath) + System.IO.Path.PathSeparator + env["PATH"]; args.Add("\"" + System.Environment.ExpandEnvironmentVariables(Program.ApplicationSettings.DuplicityPath) + "\""); + + + args.Add("incremental"); + args.Add("\"" + System.Environment.ExpandEnvironmentVariables(task.SourcePath) + "\""); + args.Add("\"" + System.Environment.ExpandEnvironmentVariables(task.GetDestinationPath()) + "\""); + + if (!string.IsNullOrEmpty(schedule.FullAfter)) + { + args.Add("--full-if-older-than"); + args.Add(schedule.FullAfter); + } + + + if (string.IsNullOrEmpty(task.Encryptionkey)) + args.Add("--no-encryption"); + else + env["PASSPHRASE"] = task.Encryptionkey; + + if (!string.IsNullOrEmpty(task.Signaturekey)) + { + args.Add("--sign-key"); + args.Add(task.Signaturekey); + } + + task.GetExtraSettings(args, env); + + + psi.CreateNoWindow = true; + psi.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden; + psi.FileName = System.Environment.ExpandEnvironmentVariables(Program.ApplicationSettings.PythonPath); + psi.RedirectStandardError = true; + psi.RedirectStandardOutput = true; + psi.RedirectStandardInput = false; + psi.UseShellExecute = false; + lock (Program.MainLock) + psi.WorkingDirectory = System.IO.Path.GetDirectoryName(psi.FileName); } - args.Add("incremental"); - args.Add("\"" + System.Environment.ExpandEnvironmentVariables(task.SourcePath) + "\""); - args.Add("\"" + System.Environment.ExpandEnvironmentVariables(task.GetDestinationPath()) + "\""); - - if (!string.IsNullOrEmpty(schedule.FullAfter)) - { - args.Add("--full-if-older-than"); - args.Add(schedule.FullAfter); - } - - if (string.IsNullOrEmpty(task.Encryptionkey)) - args.Add("--no-encryption"); - else - env["PASSPHRASE"] = task.Encryptionkey; - - if (!string.IsNullOrEmpty(task.Signaturekey)) - { - args.Add("--sign-key"); - args.Add(task.Signaturekey); - } - - task.GetExtraSettings(args, env); - - psi.CreateNoWindow = true; - psi.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden; - psi.FileName = System.Environment.ExpandEnvironmentVariables(Program.ApplicationSettings.PythonPath); - psi.RedirectStandardError = true; - psi.RedirectStandardOutput = true; - psi.RedirectStandardInput = false; - psi.UseShellExecute = false; - lock(Program.MainLock) - psi.WorkingDirectory = System.IO.Path.GetDirectoryName(psi.FileName); - psi.Arguments = string.Join(" ", args.ToArray()); System.Diagnostics.Process p = new System.Diagnostics.Process(); @@ -107,10 +110,11 @@ namespace Duplicati p.WaitForExit(); + string errorstream = p.StandardError.ReadToEnd(); string outstream = p.StandardOutput.ReadToEnd(); - string logentry = "******* Regular run *******\r\n"; + string logentry = ""; if (!string.IsNullOrEmpty(errorstream)) { string tmp = errorstream.Replace("gpg: CAST5 encrypted data", "").Replace("gpg: encrypted with 1 passphrase", "").Trim(); @@ -120,6 +124,22 @@ namespace Duplicati } logentry += outstream; + lock (Program.MainLock) + { + LogBlob lb = task.DataParent.Add(); + lb.StringData = logentry; + + Log l = task.DataParent.Add(); + l.LogBlob = lb; + task.Logs.Add(l); + + //Keep some of the data in an easy to read manner + DuplicityOutputParser.ParseData(l); + l.SubAction = "Primary"; + l.Action = "Backup"; + } + + if (schedule.KeepFull > 0) { p = new System.Diagnostics.Process(); @@ -137,10 +157,25 @@ namespace Duplicati errorstream = p.StandardError.ReadToEnd(); outstream = p.StandardOutput.ReadToEnd(); - logentry += "\r\n******* Clean up run (count) *******\r\n"; + logentry = ""; if (!string.IsNullOrEmpty(errorstream)) logentry += "** Error stream: \r\n" + errorstream + "\r\n**\r\n"; logentry += outstream; + + lock (Program.MainLock) + { + LogBlob lb = task.DataParent.Add(); + lb.StringData = logentry; + + Log l = task.DataParent.Add(); + l.LogBlob = lb; + task.Logs.Add(l); + + //Keep some of the data in an easy to read manner + DuplicityOutputParser.ParseData(l); + l.SubAction = "Cleanup"; + l.Action = "Backup"; + } } if (!string.IsNullOrEmpty(schedule.KeepTime)) @@ -161,25 +196,33 @@ namespace Duplicati errorstream = p.StandardError.ReadToEnd(); outstream = p.StandardOutput.ReadToEnd(); - logentry += "\r\n******* Clean up run (time) *******\r\n"; + logentry = ""; if (!string.IsNullOrEmpty(errorstream)) logentry += "\r\n** Error stream: \r\n" + errorstream + "\r\n**\r\n"; logentry += outstream; + + lock (Program.MainLock) + { + LogBlob lb = task.DataParent.Add(); + lb.StringData = logentry; + + Log l = task.DataParent.Add(); + l.LogBlob = lb; + task.Logs.Add(l); + + //Keep some of the data in an easy to read manner + DuplicityOutputParser.ParseData(l); + l.SubAction = "Cleanup"; + l.Action = "Backup"; + } } - LogBlob lb = task.DataParent.Add(); - lb.StringData = logentry; - - Log l = task.DataParent.Add(); - l.LogBlob = lb; - task.Logs.Add(l); - - //Keep some of the data in an easy to read manner - DuplicityOutputParser.ParseData(l); - - //TODO: Fix this once commit recursive is implemented - task.DataParent.CommitAll(); - Program.DataConnection.CommitAll(); + lock (Program.MainLock) + { + //TODO: Fix this once commit recursive is implemented + task.DataParent.CommitAll(); + Program.DataConnection.CommitAll(); + } } } } diff --git a/Duplicati/Program.cs b/Duplicati/Program.cs index 544de4a94..4a0b64c52 100644 --- a/Duplicati/Program.cs +++ b/Duplicati/Program.cs @@ -86,7 +86,7 @@ namespace Duplicati //This also opens the db for us :) DatabaseUpgrader.UpgradeDatebase(con, dbpath); - DataConnection = new DataFetcherCached(new SQLiteDataProvider(con)); + DataConnection = new DataFetcherThreadSafe(MainLock, new DataFetcherCached(new SQLiteDataProvider(con))); System.Reflection.Assembly asm = System.Reflection.Assembly.GetExecutingAssembly(); @@ -123,7 +123,7 @@ namespace Duplicati WorkThread = new WorkerThread(new WorkerThread.ProcessItemDelegate(runner.Execute)); - Scheduler = new Scheduler(DataConnection, WorkThread); + Scheduler = new Scheduler(DataConnection, WorkThread, MainLock); WorkThread.CompletedWork += new EventHandler(WorkThread_CompletedWork); WorkThread.StartingWork += new EventHandler(WorkThread_StartingWork); diff --git a/Duplicati/Scheduler.cs b/Duplicati/Scheduler.cs index a199ea161..ba5fe3cc1 100644 --- a/Duplicati/Scheduler.cs +++ b/Duplicati/Scheduler.cs @@ -34,13 +34,15 @@ namespace Duplicati private WorkerThread m_worker; private AutoResetEvent m_event; private object m_lock = new object(); + private object m_datalock; public event EventHandler NewSchedule; private Schedule[] m_schedule; - public Scheduler(IDataFetcherCached connection, WorkerThread worker) + public Scheduler(IDataFetcherCached connection, WorkerThread worker, object datalock) { + m_datalock = datalock; m_connection = connection; m_thread = new Thread(new ThreadStart(Runner)); m_worker = worker; @@ -82,8 +84,11 @@ namespace Duplicati while (!m_terminate) { List reps = new List(); + List tmp; + lock (m_datalock) + tmp = new List(m_connection.GetObjects()); - foreach (Schedule sc in m_connection.GetObjects()) + foreach (Schedule sc in tmp) { if (!string.IsNullOrEmpty(sc.Repeat)) { diff --git a/Duplicati/Service controls/TaskSettingsBase.Designer.cs b/Duplicati/Service controls/TaskSettingsBase.Designer.cs index 30c4abaf0..dd52a8c1f 100644 --- a/Duplicati/Service controls/TaskSettingsBase.Designer.cs +++ b/Duplicati/Service controls/TaskSettingsBase.Designer.cs @@ -48,22 +48,22 @@ namespace Duplicati.Service_controls private void InitializeComponent() { this.groupBox1 = new System.Windows.Forms.GroupBox(); - this.EncryptionCheckbox = new System.Windows.Forms.CheckBox(); - this.EncrytionKey = new System.Windows.Forms.TextBox(); - this.SignatureKey = new System.Windows.Forms.TextBox(); - this.SignatureCheckbox = new System.Windows.Forms.CheckBox(); - this.label1 = new System.Windows.Forms.Label(); - this.ServiceTypeCombo = new System.Windows.Forms.ComboBox(); - this.label2 = new System.Windows.Forms.Label(); - this.GenerateEncryptionKey = new System.Windows.Forms.Button(); - this.GenerateSignatureKey = new System.Windows.Forms.Button(); - this.BrowseSourceFolder = new System.Windows.Forms.Button(); - this.SourceFolder = new System.Windows.Forms.TextBox(); - this.EditFilterButton = new System.Windows.Forms.Button(); + this.ServicePanel = new System.Windows.Forms.Panel(); this.sshSettings = new Duplicati.Service_controls.SSHSettings(); this.s3Settings = new Duplicati.Service_controls.S3Settings(); this.fileSettings = new Duplicati.Service_controls.FileSettings(); - this.ServicePanel = new System.Windows.Forms.Panel(); + this.EditFilterButton = new System.Windows.Forms.Button(); + this.BrowseSourceFolder = new System.Windows.Forms.Button(); + this.SourceFolder = new System.Windows.Forms.TextBox(); + this.GenerateSignatureKey = new System.Windows.Forms.Button(); + this.GenerateEncryptionKey = new System.Windows.Forms.Button(); + this.label2 = new System.Windows.Forms.Label(); + this.ServiceTypeCombo = new System.Windows.Forms.ComboBox(); + this.label1 = new System.Windows.Forms.Label(); + this.SignatureKey = new System.Windows.Forms.TextBox(); + this.SignatureCheckbox = new System.Windows.Forms.CheckBox(); + this.EncrytionKey = new System.Windows.Forms.TextBox(); + this.EncryptionCheckbox = new System.Windows.Forms.CheckBox(); this.groupBox1.SuspendLayout(); this.ServicePanel.SuspendLayout(); this.SuspendLayout(); @@ -90,94 +90,52 @@ namespace Duplicati.Service_controls this.groupBox1.TabStop = false; this.groupBox1.Text = "Backup properties"; // - // EncryptionCheckbox + // ServicePanel // - this.EncryptionCheckbox.AutoSize = true; - this.EncryptionCheckbox.Location = new System.Drawing.Point(8, 16); - this.EncryptionCheckbox.Name = "EncryptionCheckbox"; - this.EncryptionCheckbox.Size = new System.Drawing.Size(101, 17); - this.EncryptionCheckbox.TabIndex = 0; - this.EncryptionCheckbox.Text = "Encrypt backup"; - this.EncryptionCheckbox.UseVisualStyleBackColor = true; + this.ServicePanel.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.ServicePanel.Controls.Add(this.sshSettings); + this.ServicePanel.Controls.Add(this.s3Settings); + this.ServicePanel.Controls.Add(this.fileSettings); + this.ServicePanel.Location = new System.Drawing.Point(0, 144); + this.ServicePanel.Name = "ServicePanel"; + this.ServicePanel.Size = new System.Drawing.Size(280, 272); + this.ServicePanel.TabIndex = 15; // - // EncrytionKey + // sshSettings // - this.EncrytionKey.Location = new System.Drawing.Point(112, 16); - this.EncrytionKey.Name = "EncrytionKey"; - this.EncrytionKey.Size = new System.Drawing.Size(128, 20); - this.EncrytionKey.TabIndex = 1; - this.EncrytionKey.TextChanged += new System.EventHandler(this.EncrytionKey_TextChanged); + this.sshSettings.Location = new System.Drawing.Point(96, 32); + this.sshSettings.Name = "sshSettings"; + this.sshSettings.Size = new System.Drawing.Size(88, 56); + this.sshSettings.TabIndex = 14; + this.sshSettings.Visible = false; // - // SignatureKey + // s3Settings // - this.SignatureKey.Location = new System.Drawing.Point(112, 40); - this.SignatureKey.Name = "SignatureKey"; - this.SignatureKey.Size = new System.Drawing.Size(128, 20); - this.SignatureKey.TabIndex = 3; - this.SignatureKey.TextChanged += new System.EventHandler(this.SignatureKey_TextChanged); + this.s3Settings.Location = new System.Drawing.Point(176, 32); + this.s3Settings.Name = "s3Settings"; + this.s3Settings.Size = new System.Drawing.Size(96, 56); + this.s3Settings.TabIndex = 13; + this.s3Settings.Visible = false; // - // SignatureCheckbox + // fileSettings // - this.SignatureCheckbox.AutoSize = true; - this.SignatureCheckbox.Location = new System.Drawing.Point(8, 40); - this.SignatureCheckbox.Name = "SignatureCheckbox"; - this.SignatureCheckbox.Size = new System.Drawing.Size(86, 17); - this.SignatureCheckbox.TabIndex = 2; - this.SignatureCheckbox.Text = "Sign backup"; - this.SignatureCheckbox.UseVisualStyleBackColor = true; + this.fileSettings.Location = new System.Drawing.Point(16, 32); + this.fileSettings.Name = "fileSettings"; + this.fileSettings.Size = new System.Drawing.Size(88, 64); + this.fileSettings.TabIndex = 12; + this.fileSettings.Visible = false; // - // label1 + // EditFilterButton // - this.label1.AutoSize = true; - this.label1.Location = new System.Drawing.Point(8, 120); - this.label1.Name = "label1"; - this.label1.Size = new System.Drawing.Size(81, 13); - this.label1.TabIndex = 4; - this.label1.Text = "Backup service"; - // - // ServiceTypeCombo - // - this.ServiceTypeCombo.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; - this.ServiceTypeCombo.FormattingEnabled = true; - this.ServiceTypeCombo.Items.AddRange(new object[] { - "Backup to network folder or drive", - "Backup via SSH ", - "Backup via FTP", - "Backup to Amazon S3", - "Backup to WebDAV", - "Custom "}); - this.ServiceTypeCombo.Location = new System.Drawing.Point(112, 120); - this.ServiceTypeCombo.Name = "ServiceTypeCombo"; - this.ServiceTypeCombo.Size = new System.Drawing.Size(160, 21); - this.ServiceTypeCombo.TabIndex = 5; - this.ServiceTypeCombo.SelectedIndexChanged += new System.EventHandler(this.ServiceTypeCombo_SelectedIndexChanged); - // - // label2 - // - this.label2.AutoSize = true; - this.label2.Location = new System.Drawing.Point(8, 64); - this.label2.Name = "label2"; - this.label2.Size = new System.Drawing.Size(87, 13); - this.label2.TabIndex = 6; - this.label2.Text = "Folder to backup"; - // - // GenerateEncryptionKey - // - this.GenerateEncryptionKey.Location = new System.Drawing.Point(240, 16); - this.GenerateEncryptionKey.Name = "GenerateEncryptionKey"; - this.GenerateEncryptionKey.Size = new System.Drawing.Size(24, 20); - this.GenerateEncryptionKey.TabIndex = 7; - this.GenerateEncryptionKey.UseVisualStyleBackColor = true; - this.GenerateEncryptionKey.Click += new System.EventHandler(this.GenerateEncryptionKey_Click); - // - // GenerateSignatureKey - // - this.GenerateSignatureKey.Location = new System.Drawing.Point(240, 40); - this.GenerateSignatureKey.Name = "GenerateSignatureKey"; - this.GenerateSignatureKey.Size = new System.Drawing.Size(24, 20); - this.GenerateSignatureKey.TabIndex = 8; - this.GenerateSignatureKey.UseVisualStyleBackColor = true; - this.GenerateSignatureKey.Click += new System.EventHandler(this.GenerateSignatureKey_Click); + this.EditFilterButton.Location = new System.Drawing.Point(168, 88); + this.EditFilterButton.Name = "EditFilterButton"; + this.EditFilterButton.Size = new System.Drawing.Size(96, 24); + this.EditFilterButton.TabIndex = 11; + this.EditFilterButton.Text = "Edit filter"; + this.EditFilterButton.UseVisualStyleBackColor = true; + this.EditFilterButton.Click += new System.EventHandler(this.EditFilterButton_Click); // // BrowseSourceFolder // @@ -197,49 +155,94 @@ namespace Duplicati.Service_controls this.SourceFolder.TabIndex = 9; this.SourceFolder.TextChanged += new System.EventHandler(this.SourceFolder_TextChanged); // - // EditFilterButton + // GenerateSignatureKey // - this.EditFilterButton.Location = new System.Drawing.Point(168, 88); - this.EditFilterButton.Name = "EditFilterButton"; - this.EditFilterButton.Size = new System.Drawing.Size(96, 24); - this.EditFilterButton.TabIndex = 11; - this.EditFilterButton.Text = "Edit filter"; - this.EditFilterButton.UseVisualStyleBackColor = true; - this.EditFilterButton.Click += new System.EventHandler(this.EditFilterButton_Click); + this.GenerateSignatureKey.Location = new System.Drawing.Point(240, 40); + this.GenerateSignatureKey.Name = "GenerateSignatureKey"; + this.GenerateSignatureKey.Size = new System.Drawing.Size(24, 20); + this.GenerateSignatureKey.TabIndex = 8; + this.GenerateSignatureKey.UseVisualStyleBackColor = true; + this.GenerateSignatureKey.Click += new System.EventHandler(this.GenerateSignatureKey_Click); // - // sshSettings + // GenerateEncryptionKey // - this.sshSettings.Location = new System.Drawing.Point(96, 32); - this.sshSettings.Name = "sshSettings"; - this.sshSettings.Size = new System.Drawing.Size(88, 56); - this.sshSettings.TabIndex = 14; + this.GenerateEncryptionKey.Location = new System.Drawing.Point(240, 16); + this.GenerateEncryptionKey.Name = "GenerateEncryptionKey"; + this.GenerateEncryptionKey.Size = new System.Drawing.Size(24, 20); + this.GenerateEncryptionKey.TabIndex = 7; + this.GenerateEncryptionKey.UseVisualStyleBackColor = true; + this.GenerateEncryptionKey.Click += new System.EventHandler(this.GenerateEncryptionKey_Click); // - // s3Settings + // label2 // - this.s3Settings.Location = new System.Drawing.Point(176, 32); - this.s3Settings.Name = "s3Settings"; - this.s3Settings.Size = new System.Drawing.Size(96, 56); - this.s3Settings.TabIndex = 13; + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(8, 64); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(87, 13); + this.label2.TabIndex = 6; + this.label2.Text = "Folder to backup"; // - // fileSettings + // ServiceTypeCombo // - this.fileSettings.Location = new System.Drawing.Point(16, 32); - this.fileSettings.Name = "fileSettings"; - this.fileSettings.Size = new System.Drawing.Size(88, 64); - this.fileSettings.TabIndex = 12; + this.ServiceTypeCombo.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.ServiceTypeCombo.FormattingEnabled = true; + this.ServiceTypeCombo.Items.AddRange(new object[] { + "Backup to network folder or drive", + "Backup via SSH ", + "Backup via FTP", + "Backup to Amazon S3", + "Backup to WebDAV", + "Custom "}); + this.ServiceTypeCombo.Location = new System.Drawing.Point(112, 120); + this.ServiceTypeCombo.Name = "ServiceTypeCombo"; + this.ServiceTypeCombo.Size = new System.Drawing.Size(160, 21); + this.ServiceTypeCombo.TabIndex = 5; + this.ServiceTypeCombo.SelectedIndexChanged += new System.EventHandler(this.ServiceTypeCombo_SelectedIndexChanged); // - // ServicePanel + // label1 // - this.ServicePanel.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) - | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.ServicePanel.Controls.Add(this.sshSettings); - this.ServicePanel.Controls.Add(this.s3Settings); - this.ServicePanel.Controls.Add(this.fileSettings); - this.ServicePanel.Location = new System.Drawing.Point(0, 144); - this.ServicePanel.Name = "ServicePanel"; - this.ServicePanel.Size = new System.Drawing.Size(280, 272); - this.ServicePanel.TabIndex = 15; + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(8, 120); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(81, 13); + this.label1.TabIndex = 4; + this.label1.Text = "Backup service"; + // + // SignatureKey + // + this.SignatureKey.Location = new System.Drawing.Point(112, 40); + this.SignatureKey.Name = "SignatureKey"; + this.SignatureKey.Size = new System.Drawing.Size(128, 20); + this.SignatureKey.TabIndex = 3; + this.SignatureKey.TextChanged += new System.EventHandler(this.SignatureKey_TextChanged); + // + // SignatureCheckbox + // + this.SignatureCheckbox.AutoSize = true; + this.SignatureCheckbox.Location = new System.Drawing.Point(8, 40); + this.SignatureCheckbox.Name = "SignatureCheckbox"; + this.SignatureCheckbox.Size = new System.Drawing.Size(86, 17); + this.SignatureCheckbox.TabIndex = 2; + this.SignatureCheckbox.Text = "Sign backup"; + this.SignatureCheckbox.UseVisualStyleBackColor = true; + // + // EncrytionKey + // + this.EncrytionKey.Location = new System.Drawing.Point(112, 16); + this.EncrytionKey.Name = "EncrytionKey"; + this.EncrytionKey.Size = new System.Drawing.Size(128, 20); + this.EncrytionKey.TabIndex = 1; + this.EncrytionKey.TextChanged += new System.EventHandler(this.EncrytionKey_TextChanged); + // + // EncryptionCheckbox + // + this.EncryptionCheckbox.AutoSize = true; + this.EncryptionCheckbox.Location = new System.Drawing.Point(8, 16); + this.EncryptionCheckbox.Name = "EncryptionCheckbox"; + this.EncryptionCheckbox.Size = new System.Drawing.Size(101, 17); + this.EncryptionCheckbox.TabIndex = 0; + this.EncryptionCheckbox.Text = "Encrypt backup"; + this.EncryptionCheckbox.UseVisualStyleBackColor = true; // // TaskSettingsBase // diff --git a/Duplicati/ServiceSetup.Designer.cs b/Duplicati/ServiceSetup.Designer.cs index 6b2b9efd4..bd079b5bb 100644 --- a/Duplicati/ServiceSetup.Designer.cs +++ b/Duplicati/ServiceSetup.Designer.cs @@ -52,10 +52,11 @@ namespace Duplicati this.panel1 = new System.Windows.Forms.Panel(); this.CancelBtn = new System.Windows.Forms.Button(); this.OKBtn = new System.Windows.Forms.Button(); - this.splitContainer1 = new System.Windows.Forms.SplitContainer(); - this.MainTree = new System.Windows.Forms.TreeView(); this.TreeMenuStrip = new System.Windows.Forms.ContextMenuStrip(this.components); this.playToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.imageList = new System.Windows.Forms.ImageList(this.components); + this.splitContainer1 = new System.Windows.Forms.SplitContainer(); + this.MainTree = new System.Windows.Forms.TreeView(); this.SetupMenuStrip = new System.Windows.Forms.ToolStrip(); this.AddButton = new System.Windows.Forms.ToolStripDropDownButton(); this.AddFolderMenu = new System.Windows.Forms.ToolStripMenuItem(); @@ -64,14 +65,13 @@ namespace Duplicati this.PropertyTabs = new System.Windows.Forms.TabControl(); this.OccurencePage = new System.Windows.Forms.TabPage(); this.FilePage = new System.Windows.Forms.TabPage(); - this.imageList = new System.Windows.Forms.ImageList(this.components); this.scheduleSettings = new Duplicati.Service_controls.ScheduleSettings(); this.taskSettings = new Duplicati.Service_controls.TaskSettingsBase(); this.panel1.SuspendLayout(); + this.TreeMenuStrip.SuspendLayout(); this.splitContainer1.Panel1.SuspendLayout(); this.splitContainer1.Panel2.SuspendLayout(); this.splitContainer1.SuspendLayout(); - this.TreeMenuStrip.SuspendLayout(); this.SetupMenuStrip.SuspendLayout(); this.PropertyTabs.SuspendLayout(); this.OccurencePage.SuspendLayout(); @@ -110,6 +110,29 @@ namespace Duplicati this.OKBtn.UseVisualStyleBackColor = true; this.OKBtn.Click += new System.EventHandler(this.OKBtn_Click); // + // TreeMenuStrip + // + this.TreeMenuStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.playToolStripMenuItem}); + this.TreeMenuStrip.Name = "TreeMenuStrip"; + this.TreeMenuStrip.Size = new System.Drawing.Size(165, 48); + this.TreeMenuStrip.Opening += new System.ComponentModel.CancelEventHandler(this.TreeMenuStrip_Opening); + // + // playToolStripMenuItem + // + this.playToolStripMenuItem.Image = ((System.Drawing.Image)(resources.GetObject("playToolStripMenuItem.Image"))); + this.playToolStripMenuItem.Name = "playToolStripMenuItem"; + this.playToolStripMenuItem.Size = new System.Drawing.Size(164, 22); + this.playToolStripMenuItem.Text = "Run backup now"; + this.playToolStripMenuItem.Click += new System.EventHandler(this.playToolStripMenuItem_Click); + // + // imageList + // + this.imageList.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("imageList.ImageStream"))); + this.imageList.TransparentColor = System.Drawing.Color.Transparent; + this.imageList.Images.SetKeyName(0, "Folder"); + this.imageList.Images.SetKeyName(1, "Backup"); + // // splitContainer1 // this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill; @@ -143,21 +166,6 @@ namespace Duplicati this.MainTree.AfterLabelEdit += new System.Windows.Forms.NodeLabelEditEventHandler(this.MainTree_AfterLabelEdit); this.MainTree.AfterSelect += new System.Windows.Forms.TreeViewEventHandler(this.MainTree_AfterSelect); // - // TreeMenuStrip - // - this.TreeMenuStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.playToolStripMenuItem}); - this.TreeMenuStrip.Name = "TreeMenuStrip"; - this.TreeMenuStrip.Size = new System.Drawing.Size(165, 26); - // - // playToolStripMenuItem - // - this.playToolStripMenuItem.Image = ((System.Drawing.Image)(resources.GetObject("playToolStripMenuItem.Image"))); - this.playToolStripMenuItem.Name = "playToolStripMenuItem"; - this.playToolStripMenuItem.Size = new System.Drawing.Size(164, 22); - this.playToolStripMenuItem.Text = "Run backup now"; - this.playToolStripMenuItem.Click += new System.EventHandler(this.playToolStripMenuItem_Click); - // // SetupMenuStrip // this.SetupMenuStrip.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden; @@ -182,6 +190,7 @@ namespace Duplicati this.AddButton.Name = "AddButton"; this.AddButton.Size = new System.Drawing.Size(29, 22); this.AddButton.Text = "toolStripDropDownButton1"; + this.AddButton.ToolTipText = "Add a new item"; // // AddFolderMenu // @@ -202,11 +211,14 @@ namespace Duplicati // RemoveButton // this.RemoveButton.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; + this.RemoveButton.Enabled = false; this.RemoveButton.Image = ((System.Drawing.Image)(resources.GetObject("RemoveButton.Image"))); this.RemoveButton.ImageTransparentColor = System.Drawing.Color.Magenta; this.RemoveButton.Name = "RemoveButton"; this.RemoveButton.Size = new System.Drawing.Size(23, 22); this.RemoveButton.Text = "toolStripButton2"; + this.RemoveButton.ToolTipText = "Remove the selected item"; + this.RemoveButton.Click += new System.EventHandler(this.RemoveButton_Click); // // PropertyTabs // @@ -240,13 +252,6 @@ namespace Duplicati this.FilePage.Text = "Files"; this.FilePage.UseVisualStyleBackColor = true; // - // imageList - // - this.imageList.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("imageList.ImageStream"))); - this.imageList.TransparentColor = System.Drawing.Color.Transparent; - this.imageList.Images.SetKeyName(0, "Folder"); - this.imageList.Images.SetKeyName(1, "Backup"); - // // scheduleSettings // this.scheduleSettings.Dock = System.Windows.Forms.DockStyle.Fill; @@ -275,11 +280,11 @@ namespace Duplicati this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; this.Text = "Duplicati Setup"; this.panel1.ResumeLayout(false); + this.TreeMenuStrip.ResumeLayout(false); this.splitContainer1.Panel1.ResumeLayout(false); this.splitContainer1.Panel1.PerformLayout(); this.splitContainer1.Panel2.ResumeLayout(false); this.splitContainer1.ResumeLayout(false); - this.TreeMenuStrip.ResumeLayout(false); this.SetupMenuStrip.ResumeLayout(false); this.SetupMenuStrip.PerformLayout(); this.PropertyTabs.ResumeLayout(false); diff --git a/Duplicati/ServiceSetup.cs b/Duplicati/ServiceSetup.cs index 356f17978..c148be6e9 100644 --- a/Duplicati/ServiceSetup.cs +++ b/Duplicati/ServiceSetup.cs @@ -43,10 +43,47 @@ namespace Duplicati TreeNode t = new TreeNode(s.Name); t.ImageIndex = t.SelectedImageIndex = imageList.Images.IndexOfKey("Backup"); t.Tag = s; - MainTree.Nodes.Add(t); + + if (string.IsNullOrEmpty(s.Path)) + MainTree.Nodes.Add(t); + else + FindNode(s.Path, true).Add(t); } } + private TreeNodeCollection FindNode(string path, bool allowCreate) + { + TreeNodeCollection col = MainTree.Nodes; + TreeNode match = null; + + foreach (string p in path.Split(MainTree.PathSeparator[0])) + { + match = null; + + foreach(TreeNode n in col) + if (n.Text == p) + { + match = n; + col = n.Nodes; + break; + } + + if (match == null) + if (allowCreate) + { + match = new TreeNode(p); + match.ImageIndex = match.SelectedImageIndex = imageList.Images.IndexOfKey("Folder"); + col.Add(match); + col = match.Nodes; + match.Expand(); + } + else + return MainTree.Nodes; + } + + return col; + } + private void AddFolderMenu_Click(object sender, EventArgs e) { TreeNode t = new TreeNode("New folder"); @@ -85,6 +122,7 @@ namespace Duplicati private void MainTree_AfterSelect(object sender, TreeViewEventArgs e) { + RemoveButton.Enabled = MainTree.SelectedNode != null; if (MainTree.SelectedNode == null || MainTree.SelectedNode.Tag as Schedule == null) { PropertyTabs.Visible = false; @@ -108,38 +146,116 @@ namespace Duplicati private void OKBtn_Click(object sender, EventArgs e) { //TODO: fix this when the "commit recursive" method is implemented - m_connection.CommitAll(); - Program.DataConnection.CommitAll(); + lock (Program.MainLock) + { + m_connection.CommitAll(); + Program.DataConnection.CommitAll(); + } this.DialogResult = DialogResult.OK; this.Close(); } private void MainTree_AfterLabelEdit(object sender, NodeLabelEditEventArgs e) { - if (e == null || e.Node == null || e.Node.Tag as Schedule == null) + if (e == null || e.Node == null) return; - (e.Node.Tag as Schedule).Name = e.Node.Text; - if (e.Node.FullPath != e.Node.Text) - (e.Node.Tag as Schedule).Path = e.Node.FullPath.Substring(0, e.Node.FullPath.Length - e.Node.Text.Length - MainTree.PathSeparator.Length); + e.Node.Text = e.Label; + + if (e.Node.Tag as Schedule == null) + { + Queue nodelist = new Queue(); + nodelist.Enqueue(e.Node.Nodes); + while (nodelist.Count > 0) + { + TreeNodeCollection col = nodelist.Dequeue(); + foreach (TreeNode n in col) + if (n.Nodes.Count > 0) + nodelist.Enqueue(n.Nodes); + else if (n.Tag as Schedule != null) + UpdatePathAndName(n); + } + } + else + UpdatePathAndName(e.Node); + } + + private void UpdatePathAndName(TreeNode n) + { + if (n == null || n.Tag as Schedule == null) + return; + + (n.Tag as Schedule).Name = n.Text; + if (n.FullPath != n.Text) + (n.Tag as Schedule).Path = n.FullPath.Substring(0, n.FullPath.Length - n.Text.Length - MainTree.PathSeparator.Length); } private void playToolStripMenuItem_Click(object sender, EventArgs e) { - TreeNode n = MainTree.SelectedNode; - if (n == null || n.Tag as Schedule == null) + TreeNode n = playToolStripMenuItem.Tag as TreeNode; + if (n == null) return; - /*string pgp_path = System.IO.Path.Combine(Application.StartupPath, "pgp"); - string duplicity_path = System.IO.Path.Combine(Application.StartupPath, "duplicity\\duplicity.py"); - string duplicity_lib_path = System.IO.Path.Combine(Application.StartupPath, "duplicity\\duplicity"); - string python_path = System.IO.Path.Combine(Application.StartupPath, "python25\\python.exe"); - System.Collections.Specialized.StringDictionary env = new System.Collections.Specialized.StringDictionary(); + if (n.Tag as Schedule == null) + { + Queue nodelist = new Queue(); + nodelist.Enqueue(n.Nodes); + while (nodelist.Count > 0) + { + TreeNodeCollection col = nodelist.Dequeue(); + foreach (TreeNode nx in col) + if (nx.Nodes.Count > 0) + nodelist.Enqueue(nx.Nodes); + else if (nx.Tag as Schedule != null) + Program.WorkThread.AddTask(nx.Tag as Schedule); + } + } + else + Program.WorkThread.AddTask(n.Tag as Schedule); + } - DuplicityRunner runner = new DuplicityRunner(duplicity_path, pgp_path, python_path, duplicity_lib_path, env); - runner.Execute(n.Tag as Schedule);*/ + private void RemoveButton_Click(object sender, EventArgs e) + { + if (MainTree.SelectedNode == null) + return; - Program.WorkThread.AddTask(n.Tag as Schedule); + if (MainTree.SelectedNode.Tag as Schedule != null) + { + if (MessageBox.Show(this, "Remove the backup '" + (MainTree.SelectedNode.Tag as Schedule).Name + "' ?", Application.ProductName, MessageBoxButtons.YesNoCancel) == DialogResult.Yes) + { + m_connection.DeleteObject(MainTree.SelectedNode.Tag); + MainTree.SelectedNode.Remove(); + } + } + else + { + if (MessageBox.Show(this, "Do you want to delete this folder and all the backups contained in it?", Application.ProductName, MessageBoxButtons.YesNoCancel) == DialogResult.Yes) + { + Queue nodelist = new Queue(); + nodelist.Enqueue(MainTree.SelectedNode.Nodes); + while (nodelist.Count > 0) + { + TreeNodeCollection col = nodelist.Dequeue(); + foreach (TreeNode n in col) + if (n.Nodes.Count > 0) + nodelist.Enqueue(n.Nodes); + else if (n.Tag as Schedule != null) + m_connection.DeleteObject(n.Tag); + } + + MainTree.SelectedNode.Remove(); + } + } + + } + + private void TreeMenuStrip_Opening(object sender, CancelEventArgs e) + { + Point p = MainTree.PointToClient(Cursor.Position); + TreeNode n = MainTree.GetNodeAt(p); + MainTree.SelectedNode = n; + playToolStripMenuItem.Enabled = n != null; + playToolStripMenuItem.Tag = n; } } } \ No newline at end of file diff --git a/Duplicati/ServiceSetup.resx b/Duplicati/ServiceSetup.resx index 8dd8148bb..cda52c44a 100644 --- a/Duplicati/ServiceSetup.resx +++ b/Duplicati/ServiceSetup.resx @@ -141,50 +141,49 @@ AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj0yLjAuMC4w LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0 - ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAAAI - CgAAAk1TRnQBSQFMAgEBAgEAAQQBAAEEAQABEAEAARABAAT/ASEBAAj/AUIBTQE2BwABNgMAASgDAAFA - AwABEAMAAQEBAAEgBgABEH4AAUwBFwEIAZoBRwEMAQQBg5AAAUUBCgEPAX0BRQELARABfwFFAQsBEAF/ - AUUBCwEQAX8BRQELARABfwFFAQsBEAF/AUUBCwEQAX8BRQELARABfwFFAQsBEAF/AUUBCwEQAX8BRQEL - ARABfwFFAQoBEAF/AQMCAQEDDAABRQEKAQ8BfQFFAQsBEAF/AUUBCwEQAX8BRQELARABfwFFAQsBEAF/ - AUUBCwEQAX8BRQEKAQ4BfwFFAQoBDQF/AUUBCgENAX8BRQEKAQ0BfwFKAUIBJgHMAUoB0QFwAf4BTAEg - AQoBqIgAASsBAQECAT8BjAHFAfkB/wEsAdAC/wEqAc8C/wEpAc4C/wEmAc0C/wEkAcwC/wEhAcoC/wEg - AckC/wEdAcgC/wEbAccC/wEZAcYC/wEXAcUC/wE/AVcBkAHfCAABKwEBAQIBPwGMAcUB+QH/ASwB0AL/ - ASoBzwL/ASkBzgL/ASYBzQL/ASQBzAL/AUYBygFiAf8BZwHpAZUB/wFlAekBkwH/AV8B5QGMAf8BVwHe - AYMB/wFEAc4BVQH/AUYB0wFnAf8BSgE+ARIByIQAASsCAgE/AV4BrgH3Af8BSwHdAv8BQQHaAv8BPwHZ - Av8BPQHZAv8BPAHYAv8BOgHXAv8BOAHWAv8BNQHUAv8BNAHTAv8BMgHSAv8BLwHRAv8BSAFhAYAB1wgA - ASsCAgE/AV4BrgH3Af8BSwHdAv8BQQHaAv8BPwHZAv8BPQHZAv8BPAHYAv8BSQHOAWkB/wFuAeYBgQH/ - AXUB7gGIAf8BcwHwAYcB/wFoAekBfQH/AVgB3QFrAf8BSAHRAVkB/wFEAcoBXAH+AUQBYAEbAd6AAAEr - AgIBPwF0AdQB/gH/AcYB9gH+Af8BVQHkAv8BVAHjAv8BUgHiAv8BUAHiAv8BTgHhAv8BTQHgAv8BSgHf - Av8BSQHeAv8BRwHdAv8BRQHcAv8BWgFJAVABvwEmAQEBAgE3BAABKwICAT8BdAHUAf4B/wHGAfYB/gH/ - AVUB5AL/AVQB4wL/AVIB4gL/AWMB2wHwAf8BRwHMAWYB/wFhAdYBcwH/AWwB4wGAAf8BdAHsAYcB/wF1 - AfABiQH/AWwB6wGBAf8BXAHgAXAB/wFPAdMBawH+AUUBVwEaAdiAAAErAgIBPwFxAdgC/wGHAcMB+QH/ - AWUB7AL/AWMB6wL/AWIB6wL/AWEB6gL/AWAB6gL/AV4B6QL/AV0B6AL/AVwB6AL/AVoB5wL/AVkB5gL/ - AWMBTgFQAb8BQAFXAZAB3wQAASsCAgE/AXEB2AL/AYcBwwH5Af8BZQHsAv8BYwHrAv8BkwHlAecB/wGf - AfgB9QH/AUEBxwFaAf8BVQHWAYEB/wFaAdwBhQH/AWAB4QGLAf8BYwHmAZAB/wF2AfABiQH/AW4B8AGT - Af8BMwGOAVAB94QAASsCAgE/AXoB3QL/ASMBoAH3Af8BhwHxAv8BfQHwAv8BegHwAv8BdwHwAv8BdAHw - Av8BcQHwAv8BbwHwAv8BbQHvAv8BbAHvAv8BagHvAv8BaAJQAb8BXwFrAYAB1wQAASsCAgE/AXoB3QL/ - ASMBoAH3Af8BkQHuAfcB/wG2AfgB9QH/AbQB/QH4Af8BrwHzAfEB/wGuAf0B9wH/AagB9AHxAf8BpwH3 - AfMB/wGmAfsB9QH/AV4BzgF9Af8BbgHuAZoB/wFXAYMBUQHlAV8BawGAAdeEAAErAgIBPwGKAeYC/wEx + ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAACu + CQAAAk1TRnQBSQFMAgEBAgEAAQQBAAEEAQABEAEAARABAAT/ASEBAAj/AUIBTQE2BwABNgMAASgDAAFA + AwABEAMAAQEBAAEgBgABEH4AAVACAgGaAUkCAgGDkAABRgIBAX0BRwIBAX8BRwIBAX8BRwIBAX8BRwIB + AX8BRwIBAX8BRwIBAX8BRwIBAX8BRwIBAX8BRwIBAX8BRwIBAX8BRwIBAX8BAwIBAQMMAAFGAgEBfQFH + AgEBfwFHAgEBfwFHAgEBfwFHAgEBfwFHAgEBfwFHAgEBfwFHAgEBfwFHAgEBfwFHAgEBfwFdAQUBBAHM + AVEBvgFwAf4BVAICAaiIAAErAgEBPwGMAcUB+QH/ATMB0AL/ATEBzwL/ATABzgL/AS0BzQL/ASsBzAL/ + ASgBygL/AScByQL/ASQByAL/ASIBxwL/ASABxgL/AR4BxQL/AVwBEAEYAd8IAAErAgEBPwGMAcUB+QH/ + ATMB0AL/ATEBzwL/ATABzgL/AS0BzQL/ASsBzAL/AU0BygFpAf8BbgHpAZUB/wFsAekBkwH/AWYB5QGM + Af8BXgHeAYMB/wFLAc4BXAH/AU0B0wFuAf8BXAEEAQMByIQAASsCAQE/AWUBrgH3Af8BUgHdAv8BSAHa + Av8BRgHZAv8BRAHZAv8BQwHYAv8BQQHXAv8BPwHWAv8BPAHUAv8BOwHTAv8BOQHSAv8BNgHRAv8BXgEL + AQ4B1wgAASsCAQE/AWUBrgH3Af8BUgHdAv8BSAHaAv8BRgHZAv8BRAHZAv8BQwHYAv8BUAHOAXAB/wF1 + AeYBgQH/AXwB7gGIAf8BegHwAYcB/wFvAekBgQH/AV8B3QFyAf8BTwHRAWAB/wFLAbkBXAH+AV0BEAEI + Ad6AAAErAgEBPwF7AdQB/gH/AcYB9gH+Af8BXAHkAv8BWwHjAv8BWQHiAv8BVwHiAv8BVQHhAv8BVAHg + Av8BUQHfAv8BUAHeAv8BTgHdAv8BTAHcAv8BWwIDAb8BJgIBATcEAAErAgEBPwF7AdQB/gH/AcYB9gH+ + Af8BXAHkAv8BWwHjAv8BWQHiAv8BagHbAfAB/wFOAcwBbQH/AWgB1gF6Af8BcwHjAYEB/wF7AewBhwH/ + AXwB8AGJAf8BcwHrAYEB/wFjAeABdwH/AVYBvwFrAf4BXgEJAQQB2IAAASsCAQE/AXgB2AL/AYcBwwH5 + Af8BbAHsAv8BagHrAv8BaQHrAv8BaAHqAv8BZwHqAv8BZQHpAv8BZAHoAv8BYwHoAv8BYQHnAv8BYAHm + Av8BXQIDAb8BXQEQARgB3wQAASsCAQE/AXgB2AL/AYcBwwH5Af8BbAHsAv8BagHrAv8BkwHlAecB/wGf + AfgB9QH/AUgBxwFhAf8BXAHWAYEB/wFhAdwBhQH/AWcB4QGLAf8BagHmAZAB/wF9AfABiQH/AXUB8AGT + Af8BSQFdATYB94QAASsCAQE/AYEB3QL/ASoBoAH3Af8BhwHxAv8BgQHwAv8BgQHwAv8BfgHwAv8BewHw + Av8BeAHwAv8BdgHwAv8BdAHvAv8BcwHvAv8BcQHvAv8BXQIDAb8BXwEMAQ4B1wQAASsCAQE/AYEB3QL/ + ASoBoAH3Af8BkQHuAfcB/wG2AfgB9QH/AbQB/QH4Af8BrwHzAfEB/wGuAf0B9wH/AagB9AHxAf8BpwH3 + AfMB/wGmAfsB9QH/AWUBzgGBAf8BdQHuAZoB/wFkAR4BFQHlAV8BDAEOAdeEAAErAgEBPwGKAeYC/wE4 Ac4B/gH/AekB+AH+Af8B4AH7Av8B3wH7Av8B3gH7Av8B1wH6Av8BmAH0Av8BlQH0Av8BkgH0Av8BjwH0 - Av8BjAH0Av8BcwJQAb8BcQJQAb8BKQEBAQIBPAErAgIBPwGKAeYC/wExAc4B/gH/Ae8B+AH8Af8B8QH/ - Af0B/wHvAvwB/wHvAf4B/QH/AesB/gH8Af8ByQHyAfEB/wHIAf0B+AH/AcMB9gHzAf8BagHQAX4B/wGA - AdoBmwH/AYQBeAF2AdUBcQJQAb8BKQEBAQIBPIAAASsCAgE/AZwB7wL/AVIB5AL/AVIB5AL/AVIB5AL/ - AVIB5AL/AVIB5AL/AUYBygH7Af8B8gH9Af4B/wHoAfwC/wHnAfwC/wHmAfwC/wHmAfwC/wHJArcB6wHI - ArcB6wE+AV8BmwHkASsCAgE/AZwB7wL/AVIB5AL/AVIB5AL/AfABywHEA/8B9gH/Af4B9gHuAf8BuAHQ - AeoB/wH5Av0B/wH2Af4B/QH/AfQC+gH/AfUB/gH9Af8B9AH+Af0B/wHzAvoB/wHIArcB6wE+AV8BmwHk - gAABKwICAT8BrwH5Av8BdAH0Av8BdAH0Av8BdAH0Av8BdAH0Av8BdAH0Av8BdAH0Av8BdAH0Av8BdAH0 - Av8BdAH0Av8BdAH0Av8BdAH0Av8MAAErAgIBPwGvAfkC/wF0AfQC/wF0AfQC/wF2AfQB/gL/AvMD/wH8 - Af8B+wLbAf8B/AHxAe8B/wH7AfIB7QH/AfEB0wHRAf8C/gH2Af8B8gHeAdkB/wH+AecB3gH/AaMBUAEv - AeKEAAErAgIBPwHGA/8BmgP/AZoD/wGaA/8B0AP/AeMD/wHjA/8B4wP/AeMD/wHjA/8B4wP/Ad4B/AH+ - Af8MAAErAgIBPwHGA/8BmgP/AZoD/wGaA/8B3wHeAdIF/wH9Ae8B8AH/A/4B/wH4AdkB2wH/AfoB7AHt - Af8B+wL0Af8C/gH8Af8B9AHKAYUB/wFcARQBDgGPhAABKwICAT8B6QP/AdkD/wHZA/8B2QP/AU0BPwFl - AcwoAAErAgIBPwHpA/8B2QP/AdkD/wHZA/8BTwE/AWUBzAHPAZIBhgHrBP8B/gL8Af8B+QHTAdUB/wH+ - AvwB/wH1Ad4B3wX/AfUB4wHXAf8BIwIBATGIAAFHAQsBEAF/AUgBDAEQAX8BSAEMARABfwFIAQsBEAF/ - AQ8CAQESLAABRwELARABfwFIAQwBEAF/AUgBDAEQAX8BSAELARABfwEPAgEBEgQAAf4B6gHpAf8D/gH/ - AfwB4QHiAf8B/gL9Bv8C8wH/AVgBEQEPAYjkAAEpAgIBOwH/Av0J/wHzAcwBwgH8AQ4CAQER7AABnQFV - AUoBygH/AvwB/wGGAToBMgG4+AABIQIBAS6YAAFCAU0BPgcAAT4DAAEoAwABQAMAARADAAEBAQABAQUA - AYAXAAP/AQAD/wHnBAABgAEDAYABAwUAAQMBAAEBBQABAwcAAQEHAAEBAQABAQUAAQEBAAEBFQABBwEA - AQEFAAEHAQABAQQAAQMB/wEAAQEEAAGDAf8BggEDBAAC/wH+AQcEAAP/AR8EAAP/Ab8EAAs= + Av8BjAH0Av8BXQIDAb8BXQIDAb8BKQIBATwBKwIBAT8BigHmAv8BOAHOAf4B/wHvAfgB/AH/AfEB/wH9 + Af8B7wL8Af8B7wH+Af0B/wHrAf4B/AH/AckB8gHxAf8ByAH9AfgB/wHDAfYB8wH/AXEB0AGBAf8BgQHa + AZsB/wFkAgwB1QFdAgMBvwEpAgEBPIAAASsCAQE/AZwB7wL/AVkB5AL/AVkB5AL/AVkB5AL/AVkB5AL/ + AVkB5AL/AU0BygH7Af8B8gH9Af4B/wHoAfwC/wHnAfwC/wHmAfwC/wHmAfwC/wGGAj0B6wGGAj0B6wFc + ARYBIwHkASsCAQE/AZwB7wL/AVkB5AL/AVkB5AL/AfABywHEA/8B9gH/Af4B9gHuAf8BuAHQAeoB/wH5 + Av0B/wH2Af4B/QH/AfQC+gH/AfUB/gH9Af8B9AH+Af0B/wHzAvoB/wGGAj0B6wFcARYBIwHkgAABKwIB + AT8BrwH5Av8BewH0Av8BewH0Av8BewH0Av8BewH0Av8BewH0Av8BewH0Av8BewH0Av8BewH0Av8BewH0 + Av8BewH0Av8BewH0Av8MAAErAgEBPwGvAfkC/wF7AfQC/wF7AfQC/wF9AfQB/gL/AvMD/wH8Af8B+wLb + Af8B/AHxAe8B/wH7AfIB7QH/AfEB0wHRAf8C/gH2Af8B8gHeAdkB/wH+AecB3gH/AW4BEQEMAeKEAAEr + AgEBPwHGA/8BmgP/AZoD/wGaA/8B0AP/AeMD/wHjA/8B4wP/AeMD/wHjA/8B4wP/Ad4B/AH+Af8MAAEr + AgEBPwHGA/8BmgP/AZoD/wGaA/8B3wHeAdIF/wH9Ae8B8AH/A/4B/wH4AdkB2wH/AfoB7AHtAf8B+wL0 + Af8C/gH8Af8B9AHKAYUB/wFOAgIBj4QAASsCAQE/AekD/wHZA/8B2QP/AdkD/wFdAQUBBgHMKAABKwIB + AT8B6QP/AdkD/wHZA/8B2QP/AV0BBQEGAcwBiwEyASsB6wT/Af4C/AH/AfkB0wHVAf8B/gL8Af8B9QHe + Ad8F/wH1AeMB1wH/ASMCAQExiAABRwIBAX8BRwIBAX8BRwIBAX8BRwIBAX8BDwIBARIsAAFHAgEBfwFH + AgEBfwFHAgEBfwFHAgEBfwEPAgEBEgQAAf4B6gHpAf8D/gH/AfwB4QHiAf8B/gL9Bv8C8wH/AUoCAgGI + 5AABKAIBATsB/wL9Cf8B0wGwAaUB/AEOAgEBEewAAWACBQHKAf8C/AH/AVsCAgG4+AABIQIBAS6YAAFC + AU0BPgcAAT4DAAEoAwABQAMAARADAAEBAQABAQUAAYAXAAP/AQAD/wHnBAABgAEDAYABAwUAAQMBAAEB + BQABAwcAAQEHAAEBAQABAQUAAQEBAAEBFQABBwEAAQEFAAEHAQABAQQAAQMB/wEAAQEEAAGDAf8BggED + BAAC/wH+AQcEAAP/AR8EAAP/Ab8EAAs= @@ -193,29 +192,28 @@ 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 diff --git a/Duplicati/ServiceStatus.cs b/Duplicati/ServiceStatus.cs index a0f856de3..20ceae865 100644 --- a/Duplicati/ServiceStatus.cs +++ b/Duplicati/ServiceStatus.cs @@ -64,7 +64,7 @@ namespace Duplicati //TODO: This should be protected, as the thread might change it while we itterate scheduledBackups.Items.Clear(); foreach (Schedule s in Program.Scheduler.Schedule) - scheduledBackups.Items.Add(s.When.ToString("g") + " " + s.Path); + scheduledBackups.Items.Add(s.When.ToString("g") + " " + s.Name); } } @@ -95,7 +95,7 @@ namespace Duplicati else { Schedule c = Program.WorkThread.CurrentTask; - CurrentStatus.Text = c == null ? "Waiting for next backup" : "Running " + c.Path; + CurrentStatus.Text = c == null ? "Waiting for next backup" : "Running " + c.Name; statusImage.Image = Program.WorkingImage; WorkThread_AddedWork(sender, e); } @@ -109,7 +109,7 @@ namespace Duplicati { pendingBackups.Items.Clear(); foreach (Schedule s in Program.WorkThread.CurrentTasks) - pendingBackups.Items.Add(s.Path == null ? "" : s.Path); + pendingBackups.Items.Add(s.Name == null ? "" : s.Name); } @@ -148,11 +148,15 @@ namespace Duplicati private void BuildRecent() { - Log[] logs = Program.DataConnection.GetObjects("EndTime > ? AND SubAction LIKE ? ORDER BY Time DESC", Timeparser.ParseTimeInterval(Program.ApplicationSettings.RecentBackupDuration, DateTime.Now), "Primary"); + Log[] logs; + lock(Program.MainLock) + logs = Program.DataConnection.GetObjects("EndTime > ? AND SubAction LIKE ? ORDER BY EndTime DESC", Timeparser.ParseTimeInterval(Program.ApplicationSettings.RecentBackupDuration, DateTime.Now, true), "Primary"); + + recentBackups.Items.Clear(); foreach (Log l in logs) { - ListViewItem lvi = new ListViewItem(new string[] { l.EndTime.ToString("g", System.Globalization.CultureInfo.CurrentUICulture), l.OwnerTask.Schedule.Path, l.TransferSizeString }); + ListViewItem lvi = new ListViewItem(new string[] { l.EndTime.ToString("g", System.Globalization.CultureInfo.CurrentUICulture), l.OwnerTask.Schedule.Name, l.TransferSizeString }); lvi.Tag = l; lvi.ImageIndex = imageList.Images.ContainsKey(l.ParsedStatus) ? imageList.Images.IndexOfKey(l.ParsedStatus) : imageList.Images.IndexOfKey("Warning"); @@ -173,8 +177,8 @@ namespace Duplicati LogViewer dlg = new LogViewer(); //TODO: Figure out why the LDM fails here - LogBlob lbl = l.DataParent.GetObjectById(l.LogBlobID); - dlg.LogText.Text = lbl.StringData;//l.LogBlob.StringData; + dlg.LogText.Text = l.LogBlob.StringData; + dlg.ShowDialog(this); } diff --git a/Duplicati/Timeparser.cs b/Duplicati/Timeparser.cs index fcf6eaaf6..2fad60c88 100644 --- a/Duplicati/Timeparser.cs +++ b/Duplicati/Timeparser.cs @@ -38,6 +38,14 @@ namespace Duplicati public static DateTime ParseTimeInterval(string datestring, DateTime offset) { + return ParseTimeInterval(datestring, offset, false); + } + + public static DateTime ParseTimeInterval(string datestring, DateTime offset, bool negate) + { + + int multiplier = negate ? -1 : 1; + if (string.IsNullOrEmpty(datestring)) return offset; @@ -46,7 +54,7 @@ namespace Duplicati long l; if (long.TryParse(datestring, System.Globalization.NumberStyles.Integer, null, out l)) - return offset.AddSeconds(l); + return offset.AddSeconds(l * multiplier); DateTime t; if (DateTime.TryParse(datestring, System.Globalization.CultureInfo.CurrentUICulture, System.Globalization.DateTimeStyles.None, out t)) @@ -64,6 +72,8 @@ namespace Duplicati if (!int.TryParse(partial, System.Globalization.NumberStyles.Integer, null, out factor)) throw new Exception("Failed to parse the segment: " + partial + ", invalid integer"); + factor *= multiplier; + switch (datestring[index]) { case 's':