Consolidated base forms
This commit is contained in:
parent
2c20d03506
commit
3e2d69606b
17 changed files with 242 additions and 332 deletions
|
|
@ -1,104 +0,0 @@
|
|||
namespace LibationWinForms.BookLiberation
|
||||
{
|
||||
partial class AudioDecodeBaseForm
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.pictureBox1 = new System.Windows.Forms.PictureBox();
|
||||
this.bookInfoLbl = new System.Windows.Forms.Label();
|
||||
this.progressBar1 = new System.Windows.Forms.ProgressBar();
|
||||
this.remainingTimeLbl = new System.Windows.Forms.Label();
|
||||
((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// pictureBox1
|
||||
//
|
||||
this.pictureBox1.Location = new System.Drawing.Point(14, 14);
|
||||
this.pictureBox1.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
|
||||
this.pictureBox1.Name = "pictureBox1";
|
||||
this.pictureBox1.Size = new System.Drawing.Size(117, 115);
|
||||
this.pictureBox1.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage;
|
||||
this.pictureBox1.TabIndex = 0;
|
||||
this.pictureBox1.TabStop = false;
|
||||
//
|
||||
// bookInfoLbl
|
||||
//
|
||||
this.bookInfoLbl.AutoSize = true;
|
||||
this.bookInfoLbl.Location = new System.Drawing.Point(138, 14);
|
||||
this.bookInfoLbl.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
||||
this.bookInfoLbl.Name = "bookInfoLbl";
|
||||
this.bookInfoLbl.Size = new System.Drawing.Size(121, 15);
|
||||
this.bookInfoLbl.TabIndex = 0;
|
||||
this.bookInfoLbl.Text = "[multi-line book info]";
|
||||
//
|
||||
// progressBar1
|
||||
//
|
||||
this.progressBar1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.progressBar1.Location = new System.Drawing.Point(14, 143);
|
||||
this.progressBar1.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
|
||||
this.progressBar1.Name = "progressBar1";
|
||||
this.progressBar1.Size = new System.Drawing.Size(611, 27);
|
||||
this.progressBar1.TabIndex = 2;
|
||||
//
|
||||
// remainingTimeLbl
|
||||
//
|
||||
this.remainingTimeLbl.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.remainingTimeLbl.Location = new System.Drawing.Point(632, 143);
|
||||
this.remainingTimeLbl.Name = "remainingTimeLbl";
|
||||
this.remainingTimeLbl.Size = new System.Drawing.Size(60, 31);
|
||||
this.remainingTimeLbl.TabIndex = 3;
|
||||
this.remainingTimeLbl.Text = "ETA:\r\n";
|
||||
this.remainingTimeLbl.TextAlign = System.Drawing.ContentAlignment.TopRight;
|
||||
//
|
||||
// DecryptForm
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(707, 183);
|
||||
this.Controls.Add(this.remainingTimeLbl);
|
||||
this.Controls.Add(this.progressBar1);
|
||||
this.Controls.Add(this.bookInfoLbl);
|
||||
this.Controls.Add(this.pictureBox1);
|
||||
this.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
|
||||
this.Name = "DecryptForm";
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
||||
this.Text = "DecryptForm";
|
||||
((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit();
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.PictureBox pictureBox1;
|
||||
private System.Windows.Forms.Label bookInfoLbl;
|
||||
private System.Windows.Forms.ProgressBar progressBar1;
|
||||
private System.Windows.Forms.Label remainingTimeLbl;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,126 +0,0 @@
|
|||
using DataLayer;
|
||||
using Dinah.Core.Net.Http;
|
||||
using Dinah.Core.Windows.Forms;
|
||||
using FileLiberator;
|
||||
using System;
|
||||
|
||||
namespace LibationWinForms.BookLiberation
|
||||
{
|
||||
public partial class AudioDecodeBaseForm : ProcessBaseForm
|
||||
{
|
||||
public virtual string DecodeActionName { get; } = "Decoding";
|
||||
public AudioDecodeBaseForm() => InitializeComponent();
|
||||
|
||||
private Func<byte[]> GetCoverArtDelegate;
|
||||
|
||||
// book info
|
||||
private string title;
|
||||
private string authorNames;
|
||||
private string narratorNames;
|
||||
|
||||
#region ProcessBaseForm overrides
|
||||
public override void SetProcessable(IStreamable streamProcessable, LogMe logMe)
|
||||
{
|
||||
base.SetProcessable(streamProcessable, logMe);
|
||||
|
||||
if (Streamable is not null && Streamable is IAudioDecodable audioDecodable)
|
||||
{
|
||||
OnUnsubscribeAll(this, EventArgs.Empty);
|
||||
|
||||
audioDecodable.RequestCoverArt += OnRequestCoverArt;
|
||||
audioDecodable.TitleDiscovered += OnTitleDiscovered;
|
||||
audioDecodable.AuthorsDiscovered += OnAuthorsDiscovered;
|
||||
audioDecodable.NarratorsDiscovered += OnNarratorsDiscovered;
|
||||
audioDecodable.CoverImageDiscovered += OnCoverImageDiscovered;
|
||||
|
||||
Disposed += OnUnsubscribeAll;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
private void OnUnsubscribeAll(object sender, EventArgs e)
|
||||
{
|
||||
if (Streamable is IAudioDecodable audioDecodable)
|
||||
{
|
||||
Disposed -= OnUnsubscribeAll;
|
||||
audioDecodable.RequestCoverArt -= OnRequestCoverArt;
|
||||
audioDecodable.TitleDiscovered -= OnTitleDiscovered;
|
||||
audioDecodable.AuthorsDiscovered -= OnAuthorsDiscovered;
|
||||
audioDecodable.NarratorsDiscovered -= OnNarratorsDiscovered;
|
||||
audioDecodable.CoverImageDiscovered -= OnCoverImageDiscovered;
|
||||
|
||||
audioDecodable.Cancel();
|
||||
}
|
||||
}
|
||||
|
||||
#region IProcessable event handler overrides
|
||||
public override void OnBegin(object sender, LibraryBook libraryBook)
|
||||
{
|
||||
GetCoverArtDelegate = () => FileManager.PictureStorage.GetPictureSynchronously(
|
||||
new FileManager.PictureDefinition(
|
||||
libraryBook.Book.PictureId,
|
||||
FileManager.PictureSize._500x500));
|
||||
|
||||
//Set default values from library
|
||||
OnTitleDiscovered(sender, libraryBook.Book.Title);
|
||||
OnAuthorsDiscovered(sender, string.Join(", ", libraryBook.Book.Authors));
|
||||
OnNarratorsDiscovered(sender, string.Join(", ", libraryBook.Book.NarratorNames));
|
||||
OnCoverImageDiscovered(sender,
|
||||
FileManager.PictureStorage.GetPicture(
|
||||
new FileManager.PictureDefinition(
|
||||
libraryBook.Book.PictureId,
|
||||
FileManager.PictureSize._80x80)).bytes);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region IStreamable event handler overrides
|
||||
public override void OnStreamingProgressChanged(object sender, DownloadProgress downloadProgress)
|
||||
{
|
||||
if (!downloadProgress.ProgressPercentage.HasValue)
|
||||
return;
|
||||
|
||||
if (downloadProgress.ProgressPercentage == 0)
|
||||
updateRemainingTime(0);
|
||||
else
|
||||
progressBar1.UIThread(() => progressBar1.Value = (int)downloadProgress.ProgressPercentage);
|
||||
}
|
||||
|
||||
public override void OnStreamingTimeRemaining(object sender, TimeSpan timeRemaining)
|
||||
=> updateRemainingTime((int)timeRemaining.TotalSeconds);
|
||||
#endregion
|
||||
|
||||
#region IAudioDecodable event handlers
|
||||
public virtual void OnRequestCoverArt(object sender, Action<byte[]> setCoverArtDelegate)
|
||||
=> setCoverArtDelegate(GetCoverArtDelegate?.Invoke());
|
||||
|
||||
public virtual void OnTitleDiscovered(object sender, string title)
|
||||
{
|
||||
this.UIThread(() => this.Text = DecodeActionName + " " + title);
|
||||
this.title = title;
|
||||
updateBookInfo();
|
||||
}
|
||||
|
||||
public virtual void OnAuthorsDiscovered(object sender, string authors)
|
||||
{
|
||||
authorNames = authors;
|
||||
updateBookInfo();
|
||||
}
|
||||
|
||||
public virtual void OnNarratorsDiscovered(object sender, string narrators)
|
||||
{
|
||||
narratorNames = narrators;
|
||||
updateBookInfo();
|
||||
}
|
||||
|
||||
public virtual void OnCoverImageDiscovered(object sender, byte[] coverArt)
|
||||
=> pictureBox1.UIThread(() => pictureBox1.Image = Dinah.Core.Drawing.ImageReader.ToImage(coverArt));
|
||||
#endregion
|
||||
|
||||
// thread-safe UI updates
|
||||
private void updateBookInfo()
|
||||
=> bookInfoLbl.UIThread(() => bookInfoLbl.Text = $"{title}\r\nBy {authorNames}\r\nNarrated by {narratorNames}");
|
||||
|
||||
private void updateRemainingTime(int remaining)
|
||||
=> remainingTimeLbl.UIThread(() => remainingTimeLbl.Text = $"ETA:\r\n{remaining} sec");
|
||||
}
|
||||
}
|
||||
|
|
@ -1,61 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
||||
189
LibationWinForms/BookLiberation/BaseForms/LiberationBaseForm.cs
Normal file
189
LibationWinForms/BookLiberation/BaseForms/LiberationBaseForm.cs
Normal file
|
|
@ -0,0 +1,189 @@
|
|||
using DataLayer;
|
||||
using Dinah.Core.Net.Http;
|
||||
using Dinah.Core.Windows.Forms;
|
||||
using FileLiberator;
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace LibationWinForms.BookLiberation.BaseForms
|
||||
{
|
||||
public abstract class LiberationBaseForm : Form
|
||||
{
|
||||
protected IFileLiberator Liberation { get; private set; }
|
||||
protected LogMe LogMe { get; private set; }
|
||||
|
||||
private int InstanceThreadId { get; } = Thread.CurrentThread.ManagedThreadId;
|
||||
public new bool InvokeRequired => Thread.CurrentThread.ManagedThreadId != InstanceThreadId;
|
||||
private SynchronizationContext SyncContext { get; }
|
||||
|
||||
public LiberationBaseForm()
|
||||
{
|
||||
//Will be null if set outside constructor.
|
||||
SyncContext = SynchronizationContext.Current;
|
||||
}
|
||||
|
||||
public void RegisterLiberation(IFileLiberator liberation, LogMe logMe = null)
|
||||
{
|
||||
if (liberation is null) return;
|
||||
|
||||
Liberation = liberation;
|
||||
LogMe = logMe;
|
||||
|
||||
if (Liberation is IStreamable streamable)
|
||||
Subscribe(streamable);
|
||||
if (Liberation is IProcessable processable)
|
||||
Subscribe(processable);
|
||||
if (Liberation is IAudioDecodable audioDecodable)
|
||||
Subscribe(audioDecodable);
|
||||
}
|
||||
|
||||
#region Event Subscribers and Unsubscribers
|
||||
private void Subscribe(IStreamable streamable)
|
||||
{
|
||||
UnsubscribeStreamable(this, EventArgs.Empty);
|
||||
|
||||
streamable.StreamingBegin += ShowFormHandler;
|
||||
streamable.StreamingBegin += OnStreamingBegin;
|
||||
streamable.StreamingProgressChanged += OnStreamingProgressChanged;
|
||||
streamable.StreamingTimeRemaining += OnStreamingTimeRemaining;
|
||||
streamable.StreamingCompleted += OnStreamingCompleted;
|
||||
streamable.StreamingCompleted += OnStreamingCompletedClose;
|
||||
|
||||
FormClosed += UnsubscribeStreamable;
|
||||
}
|
||||
private void Subscribe(IProcessable processable)
|
||||
{
|
||||
UnsubscribeProcessable(this, null);
|
||||
|
||||
processable.Begin += OnBegin;
|
||||
processable.StatusUpdate += OnStatusUpdate;
|
||||
processable.Completed += OnCompleted;
|
||||
|
||||
//The form is created on IProcessable.Begin and we
|
||||
//dispose of it on IProcessable.Completed
|
||||
processable.Completed += OnCompletedDispose;
|
||||
|
||||
//Don't unsubscribe from Dispose because it fires when
|
||||
//IStreamable.StreamingCompleted closes the form, and
|
||||
//the IProcessable events need to live past that event.
|
||||
processable.Completed += UnsubscribeProcessable;
|
||||
}
|
||||
private void Subscribe(IAudioDecodable audioDecodable)
|
||||
{
|
||||
UnsubscribeAudioDecodable(this, EventArgs.Empty);
|
||||
|
||||
audioDecodable.RequestCoverArt += OnRequestCoverArt;
|
||||
audioDecodable.TitleDiscovered += OnTitleDiscovered;
|
||||
audioDecodable.AuthorsDiscovered += OnAuthorsDiscovered;
|
||||
audioDecodable.NarratorsDiscovered += OnNarratorsDiscovered;
|
||||
audioDecodable.CoverImageDiscovered += OnCoverImageDiscovered;
|
||||
|
||||
Disposed += UnsubscribeAudioDecodable;
|
||||
}
|
||||
private void UnsubscribeStreamable(object sender, EventArgs e)
|
||||
{
|
||||
if (Liberation is not IStreamable streamable)
|
||||
return;
|
||||
|
||||
FormClosed -= UnsubscribeStreamable;
|
||||
|
||||
streamable.StreamingBegin -= ShowFormHandler;
|
||||
streamable.StreamingBegin -= OnStreamingBegin;
|
||||
streamable.StreamingProgressChanged -= OnStreamingProgressChanged;
|
||||
streamable.StreamingTimeRemaining -= OnStreamingTimeRemaining;
|
||||
streamable.StreamingCompleted -= OnStreamingCompleted;
|
||||
streamable.StreamingCompleted -= OnStreamingCompletedClose;
|
||||
}
|
||||
private void UnsubscribeProcessable(object sender, LibraryBook e)
|
||||
{
|
||||
if (Liberation is not IProcessable processable)
|
||||
return;
|
||||
|
||||
processable.Completed -= UnsubscribeProcessable;
|
||||
processable.Completed -= OnCompletedDispose;
|
||||
processable.Completed -= OnCompleted;
|
||||
processable.StatusUpdate -= OnStatusUpdate;
|
||||
processable.Begin -= OnBegin;
|
||||
}
|
||||
private void UnsubscribeAudioDecodable(object sender, EventArgs e)
|
||||
{
|
||||
if (Liberation is not IAudioDecodable audioDecodable)
|
||||
return;
|
||||
|
||||
Disposed -= UnsubscribeAudioDecodable;
|
||||
audioDecodable.RequestCoverArt -= OnRequestCoverArt;
|
||||
audioDecodable.TitleDiscovered -= OnTitleDiscovered;
|
||||
audioDecodable.AuthorsDiscovered -= OnAuthorsDiscovered;
|
||||
audioDecodable.NarratorsDiscovered -= OnNarratorsDiscovered;
|
||||
audioDecodable.CoverImageDiscovered -= OnCoverImageDiscovered;
|
||||
|
||||
audioDecodable.Cancel();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Form creation and disposal handling
|
||||
|
||||
/// <summary>
|
||||
/// If the form was shown using Show (not ShowDialog), Form.Close calls Form.Dispose
|
||||
/// </summary>
|
||||
private void OnStreamingCompletedClose(object sender, string completedString) => this.UIThread(() => Close());
|
||||
private void OnCompletedDispose(object sender, LibraryBook e) => this.UIThread(() => Dispose());
|
||||
|
||||
/// <summary>
|
||||
/// If StreamingBegin is fired from a worker thread, the window will be created on
|
||||
/// that UI thread. We need to make certain that we show the window on the same
|
||||
/// thread that created form, otherwise the form and the window handle will be on
|
||||
/// different threads. Form.BeginInvoke won't work until the form is created
|
||||
/// (ie. shown) because control doesn't get a window handle until it is Shown.
|
||||
/// </summary>
|
||||
private void ShowFormHandler(object sender, string beginString)
|
||||
{
|
||||
static void sendCallback(object asyncArgs)
|
||||
{
|
||||
var e = asyncArgs as AsyncCompletedEventArgs;
|
||||
((Action)e.UserState)();
|
||||
}
|
||||
|
||||
Action show = Show;
|
||||
|
||||
if (InvokeRequired)
|
||||
SyncContext.Send(
|
||||
sendCallback,
|
||||
new AsyncCompletedEventArgs(null, false, show));
|
||||
else
|
||||
show();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region IStreamable event handlers
|
||||
public virtual void OnStreamingBegin(object sender, string beginString) { }
|
||||
public virtual void OnStreamingProgressChanged(object sender, DownloadProgress downloadProgress){ }
|
||||
public virtual void OnStreamingTimeRemaining(object sender, TimeSpan timeRemaining){ }
|
||||
public virtual void OnStreamingCompleted(object sender, string completedString){ }
|
||||
#endregion
|
||||
|
||||
#region IProcessable event handlers
|
||||
public virtual void OnBegin(object sender, LibraryBook libraryBook){ }
|
||||
public virtual void OnStatusUpdate(object sender, string statusUpdate){ }
|
||||
public virtual void OnCompleted(object sender, LibraryBook libraryBook){ }
|
||||
#endregion
|
||||
|
||||
#region IAudioDecodable event handlers
|
||||
public virtual void OnRequestCoverArt(object sender, Action<byte[]> setCoverArtDelegate){ }
|
||||
public virtual void OnTitleDiscovered(object sender, string title){ }
|
||||
public virtual void OnAuthorsDiscovered(object sender, string authors){ }
|
||||
public virtual void OnNarratorsDiscovered(object sender, string narrators){ }
|
||||
public virtual void OnCoverImageDiscovered(object sender, byte[] coverArt){ }
|
||||
#endregion
|
||||
}
|
||||
|
||||
#region VS Design View Hack
|
||||
/// <summary>
|
||||
/// This class is a hack so that VS designer will work wif an abstract base class.
|
||||
/// https://stackoverflow.com/questions/1620847/how-can-i-get-visual-studio-2008-windows-forms-designer-to-render-a-form-that-im/2406058#2406058
|
||||
/// </summary>
|
||||
public class DebugIntermediate : LiberationBaseForm { }
|
||||
#endregion
|
||||
}
|
||||
|
|
@ -1,54 +0,0 @@
|
|||
using DataLayer;
|
||||
using Dinah.Core.Windows.Forms;
|
||||
using FileLiberator;
|
||||
using System;
|
||||
|
||||
namespace LibationWinForms.BookLiberation
|
||||
{
|
||||
public class ProcessBaseForm : StreamBaseForm
|
||||
{
|
||||
protected LogMe LogMe { get; private set; }
|
||||
public virtual void SetProcessable(IStreamable streamable, LogMe logMe)
|
||||
{
|
||||
LogMe = logMe;
|
||||
SetStreamable(streamable);
|
||||
|
||||
if (Streamable is not null && Streamable is IProcessable processable)
|
||||
{
|
||||
OnUnsubscribeAll(this, null);
|
||||
|
||||
processable.Begin += OnBegin;
|
||||
processable.Completed += OnCompleted;
|
||||
processable.StatusUpdate += OnStatusUpdate;
|
||||
|
||||
//The form is created on IProcessable.Begin and we
|
||||
//dispose of it on IProcessable.Completed
|
||||
processable.Completed += OnCompletedDispose;
|
||||
|
||||
//Don't unsubscribe from Dispose because it fires when
|
||||
//IStreamable.StreamingCompleted closes the form, and
|
||||
//the IProcessable events need to live past that event.
|
||||
processable.Completed += OnUnsubscribeAll;
|
||||
}
|
||||
}
|
||||
private void OnCompletedDispose(object sender, LibraryBook e) => this.UIThread(() => Dispose());
|
||||
|
||||
private void OnUnsubscribeAll(object sender, LibraryBook e)
|
||||
{
|
||||
if (Streamable is IProcessable processable)
|
||||
{
|
||||
processable.Completed -= OnUnsubscribeAll;
|
||||
processable.Completed -= OnCompletedDispose;
|
||||
processable.Begin -= OnBegin;
|
||||
processable.Completed -= OnCompleted;
|
||||
processable.StatusUpdate -= OnStatusUpdate;
|
||||
}
|
||||
}
|
||||
|
||||
#region IProcessable event handlers
|
||||
public virtual void OnBegin(object sender, LibraryBook libraryBook) => LogMe.Info($"Begin: {libraryBook.Book}");
|
||||
public virtual void OnStatusUpdate(object sender, string statusUpdate) => LogMe.Info("- " + statusUpdate);
|
||||
public virtual void OnCompleted(object sender, LibraryBook libraryBook) => LogMe.Info($"Completed: {libraryBook.Book}{Environment.NewLine}");
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
@ -1,61 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
||||
|
|
@ -1,90 +0,0 @@
|
|||
using Dinah.Core.Net.Http;
|
||||
using Dinah.Core.Windows.Forms;
|
||||
using FileLiberator;
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace LibationWinForms.BookLiberation
|
||||
{
|
||||
public class StreamBaseForm : Form
|
||||
{
|
||||
private int InstanceThreadId { get; } = Thread.CurrentThread.ManagedThreadId;
|
||||
public new bool InvokeRequired => Thread.CurrentThread.ManagedThreadId != InstanceThreadId;
|
||||
private SynchronizationContext SyncContext { get; }
|
||||
|
||||
public StreamBaseForm()
|
||||
{
|
||||
//Will be null if set outside constructor.
|
||||
SyncContext = SynchronizationContext.Current;
|
||||
}
|
||||
|
||||
protected IStreamable Streamable { get; private set; }
|
||||
public void SetStreamable(IStreamable streamable)
|
||||
{
|
||||
Streamable = streamable;
|
||||
|
||||
if (Streamable is null) return;
|
||||
|
||||
OnUnsubscribeAll(this, EventArgs.Empty);
|
||||
|
||||
Streamable.StreamingBegin += ShowFormHandler;
|
||||
Streamable.StreamingBegin += OnStreamingBegin;
|
||||
Streamable.StreamingProgressChanged += OnStreamingProgressChanged;
|
||||
Streamable.StreamingTimeRemaining += OnStreamingTimeRemaining;
|
||||
Streamable.StreamingCompleted += OnStreamingCompleted;
|
||||
Streamable.StreamingCompleted += CloseFormHandler;
|
||||
|
||||
FormClosed += OnUnsubscribeAll;
|
||||
}
|
||||
|
||||
private void OnUnsubscribeAll(object sender, EventArgs e)
|
||||
{
|
||||
FormClosed -= OnUnsubscribeAll;
|
||||
|
||||
Streamable.StreamingBegin -= ShowFormHandler;
|
||||
Streamable.StreamingBegin -= OnStreamingBegin;
|
||||
Streamable.StreamingProgressChanged -= OnStreamingProgressChanged;
|
||||
Streamable.StreamingTimeRemaining -= OnStreamingTimeRemaining;
|
||||
Streamable.StreamingCompleted -= OnStreamingCompleted;
|
||||
Streamable.StreamingCompleted -= CloseFormHandler;
|
||||
}
|
||||
|
||||
private void ShowFormHandler(object sender, string beginString)
|
||||
{
|
||||
//If StreamingBegin is fired from a worker thread, the window will be created on
|
||||
//that UI thread. We need to make certain that we show the window on the same
|
||||
//thread that created form, otherwise the form and the window handle will be on
|
||||
//different threads. Form.BeginInvoke won't work until the form is created
|
||||
//(ie. shown) because control doesn't get a window handle until it is Shown.
|
||||
static void sendCallback(object asyncArgs)
|
||||
{
|
||||
var e = asyncArgs as AsyncCompletedEventArgs;
|
||||
((Action)e.UserState)();
|
||||
}
|
||||
|
||||
Action show = Show;
|
||||
|
||||
if (InvokeRequired)
|
||||
SyncContext.Send(
|
||||
sendCallback,
|
||||
new AsyncCompletedEventArgs(null, false, show));
|
||||
else
|
||||
show();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If the form was shown using Show (not ShowDialog), Form.Close calls Form.Dispose
|
||||
/// </summary>
|
||||
private void CloseFormHandler(object sender, string completedString) => this.UIThread(() => Close());
|
||||
|
||||
|
||||
#region IStreamable event handlers
|
||||
public virtual void OnStreamingBegin(object sender, string beginString) { }
|
||||
public virtual void OnStreamingProgressChanged(object sender, DownloadProgress downloadProgress) { }
|
||||
public virtual void OnStreamingTimeRemaining(object sender, TimeSpan timeRemaining) { }
|
||||
public virtual void OnStreamingCompleted(object sender, string completedString) { }
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
@ -1,61 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
||||
Loading…
Add table
Add a link
Reference in a new issue