📄 downloadform.cs
字号:
/************************************************************
DownloadForm.cs
Displays the status of an active download while the data is
saved to a file
Revision history:
November 15, 2000, by Scott Glasgow
Added close window when user selects to stop the download
November 16, 2000, by Scott Glasgow
Added some clean-up when there is a connection error. Basically, the app creates the file before a connection
so if we don't connect, we now cleanup the file.
Added file closing on connection error. For some reason it wasn't being closed and this caused an exception in
certain areas.
Added some status updates although they probably won't be seen unless it takes a while to connect, etc.
November 17, 2000 by Joe Hardy
- All code was split into modules from downloader.cs (now obsolete)
- A few mods to Scott's changes
January 20, 2001 by Joe Hardy
- Updated code to work with changes in TransferStuff.cs
Late June - 6 July, 2000 by Joe Hardy
- Cut all the code across to work with beta 2
************************************************************/
using System;
using System.Windows.Forms;
using System.Drawing;
using System.IO;
using System.ComponentModel;
public class DownloadForm : Form {
JobData jobData;
// set in places like StopDownload and cmdPause_Click, checked in StartDownload()
bool stopdownload=false;
bool closewindow=false;
bool deletefile=false;
// Checked in StopDownload so the function isn't run twice (say the user hit
// the Stop button and the Form_Closing event was triggered)
bool handledclose=false;
// There are some cases where the user does not need to be asked if they want
// to overwrite or resume a file. This variable is set within the constructor
// and checked at the beginning of StartDownload(). Yes, I know I could have
// used stopdownload rather than adding another boolean, but I figured this
// made things easier in terms of readability
bool queryresume=false;
// boolean that tells us whether the current download is resumable or not.
bool resumable=true;
Label lblDownloadingFrom = new Label();
Label lblUrl = new Label();
Label lblDownloadingTo = new Label();
Label lblLocalPath = new Label();
Label lblTimeLeft = new Label();
Label lblTime = new Label();
Label lblSpeed = new Label();
Label lblRate = new Label();
Label lblDownloaded = new Label();
Label lblReceivedData = new Label();
Label lblNotResumable = new Label();
ProgressBar pb = new ProgressBar();
Button cmdShowDetails = new Button();
Button cmdStop = new Button();
Button cmdPause = new Button();
public TextBox txtDetails = new TextBox();
public DownloadForm(JobData jobData, bool queryresume) {
this.jobData=jobData;
this.queryresume=queryresume;
// set up the controls
this.FormBorderStyle=FormBorderStyle.FixedDialog;
this.Closing += new CancelEventHandler(this.Form_Closing);
this.Size = new Size(360, 219);
this.Text = "0% completed of " + jobData.localName;
this.MaximizeBox = false;
this.MinimizeBox = false;
lblDownloadingFrom.Text = "Downloading From ...";
lblDownloadingFrom.Location = new Point(8, 8);
lblDownloadingFrom.Size = new Size(111, 13);
lblDownloadingFrom.Font = new Font(this.Font.FontFamily, this.Font.SizeInPoints, FontStyle.Bold);
lblUrl.Location = new Point(8, 24);
lblUrl.Text = jobData.url;
lblUrl.Size = new Size(this.Width-20, 13);
lblDownloadingTo.Text = "To ...";
lblDownloadingTo.Location = new Point(8, 40);
lblDownloadingTo.Size = new Size(32, 13);
lblDownloadingTo.Font = new Font(this.Font.FontFamily, this.Font.SizeInPoints, FontStyle.Bold);
lblLocalPath.Text = jobData.localPath + jobData.localName;
lblLocalPath.Location = new Point(8, 56);
lblLocalPath.Size = new Size(this.Width-20, 13);
lblTimeLeft.Text = "Time left:";
lblTimeLeft.Location = new Point(8, 88);
lblTimeLeft.Size = new Size(54, 13);
lblTime.Text = "unknown";
lblTime.Location = new Point(88, 88);
lblTime.Size = new Size(75, 13);
lblSpeed.Text = "Speed:";
lblSpeed.Location = new Point(8, 104);
lblSpeed.Size = new Size(41, 13);
lblRate.Text = "unknown";
lblRate.Location = new Point(88, 104);
lblRate.Size = new Size(150, 13);
lblDownloaded.Text = "Downloaded:";
lblDownloaded.Location = new Point(8, 120);
lblDownloaded.Size = new Size(75, 13);
lblReceivedData.Text = "unknown";
lblReceivedData.Location = new Point(88, 120);
lblReceivedData.Size = new Size(180, 13);
pb.Size = new Size(338, 10);
pb.Location = new Point(8, 143);
cmdShowDetails.Location = new Point(96, 165);
cmdShowDetails.Text = "&Show Details";
cmdShowDetails.Click += new EventHandler(cmdShowDetails_Click);
cmdStop.Location = new Point(184, 165);
cmdStop.Text = "&Stop";
cmdStop.Click += new EventHandler(cmdStop_Click);
cmdPause.Location = new Point(272, 165);
cmdPause.Text = "&Pause";
cmdPause.Click += new EventHandler(cmdPause_Click);
txtDetails.Location = new Point(8, this.Height - 15);
txtDetails.Size = new Size(this.Width - 22, 135);
txtDetails.Text = "(unimplemented)";
lblNotResumable.Text = "(unresumable)";
lblNotResumable.Visible = false;
lblNotResumable.AutoSize = true;
lblNotResumable.Location = new Point(272, 125);
this.Controls.Add(lblDownloadingFrom);
this.Controls.Add(lblUrl);
this.Controls.Add(lblDownloadingTo);
this.Controls.Add(lblLocalPath);
this.Controls.Add(lblTimeLeft);
this.Controls.Add(lblTime);
this.Controls.Add(lblSpeed);
this.Controls.Add(lblRate);
this.Controls.Add(lblDownloaded);
this.Controls.Add(lblReceivedData);
this.Controls.Add(cmdShowDetails);
this.Controls.Add(cmdStop);
this.Controls.Add(cmdPause);
this.Controls.Add(txtDetails);
this.Controls.Add(pb);
this.Controls.Add(lblNotResumable);
// show the form
this.Show();
}
public void cmdPause_Click(Object Src, EventArgs e) {
// this variable will be picked up in StartDownload() and acted on there
if (stopdownload) {
StartDownload();
lblReceivedData.Text = "Downloading";
}
else {
stopdownload=true;
lblReceivedData.Text = "Paused";
}
}
public void cmdStop_Click(Object Src, EventArgs e) {
lblReceivedData.Text = "Stopping Download";
StopDownload();
}
public void cmdShowDetails_Click(Object Src, EventArgs e) {
if (this.Height==219) {
cmdShowDetails.Text = "&Hide Details";
this.Height=370;
}
else {
cmdShowDetails.Text = "&Show Details";
this.Height=219;
}
}
public void Form_Closing(Object Src, CancelEventArgs e) {
if (!handledclose) StopDownload();
}
public void StopDownload() {
DialogResult result;
// confirm the user's decision
if (resumable)
result = MessageBox.Show("Do you want to continue downloading this file later on?\n\nClicking no will delete the data that has been downloaded so far.", "Cancel Download?", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);
else
result = MessageBox.Show("This transfer is unresumable. Are you sure you want to cancel this download?\n\nClicking OK will delete the data downloaded so far.", "Cancel Download?", MessageBoxButtons.OKCancel, MessageBoxIcon.Question);
// the variables set here are read towards the end of DownloadForm.StartDownload(). Have a gander
// down there if you're wondering exactly what they do
if (result==DialogResult.Yes) {
stopdownload=true;
closewindow=true;
}
else if (result==DialogResult.No || result == DialogResult.OK) {
stopdownload=true;
lblReceivedData.Text = "Deleting File";
deletefile=true;
closewindow=true;
}
if (closewindow) {
handledclose=true;
this.Close();
this.Dispose();
}
}
public void StartDownload() {
// make sure we're on top to start with
this.Activate();
// a few variable declarations
long startfrom=0; // used in the Range HTTP header
string filePath = jobData.localPath + jobData.localName; // full path to the file we're going to save our data to
NewTransfer nt = new NewTransfer(); // new instance of the NewTransfer class
// does the file the user specified exist. if so, ask them if they want to overwrite
// the file or resume the download.
FileMode filemode = FileMode.Create;
lblReceivedData.Text = "Checking for local file";
if (File.Exists(filePath) && !stopdownload && queryresume) {
DialogResult result = MessageBox.Show("The file you specified already exists. Would you like to resume it?", "File already exists!", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Exclamation);
this.Activate();
if (result == DialogResult.Yes) {
// we want to append to the existing file
lblReceivedData.Text = "Setting To Append To File";
filemode = FileMode.Append;
}
else if (result == DialogResult.No) {
// we want to overwrite the file
lblReceivedData.Text = "Setting To Overwrite File";
filemode = FileMode.Create;
}
else {
// user hit cancel, so dispose this class
lblReceivedData.Text = "Cancelling Job";
this.Close();
this.Dispose();
return;
}
}
// this download has been paused during this session, or resumed from the job list on
// MainForm, so obviously the asking the above question would be illogical.
else if (stopdownload || !queryresume) {
filemode = FileMode.Append;
stopdownload=false;
}
// Create a filestream object opening/creating (whatevers been defined in filemode)
// the file we're going to save our data to. I'm allowing read-only sharing because
// I sometimes like to listen to mp3s I'm downloading while they're still coming :-)
FileStream fs = new FileStream(filePath, filemode, FileAccess.Write, FileShare.Read);
// just in case a bit of data got mangled at the end of the file, we'll backtrack by
// 4KB (if that much data is available)
if (fs.Length > 4096) {
startfrom=fs.Length-4096;
fs.Position=startfrom;
}
long filesize;
// HTTP request sent off here
try {
lblReceivedData.Text = "Connecting To Server";
filesize = nt.GetUrl(jobData.url, startfrom);
lblReceivedData.Text = "Connected";
}
catch (Exception e) {
handledclose=true;
lblReceivedData.Text = "Closing File";
fs.Close();
// You should probably check to see if the file being downloaded was created, and delete it if it exists.
lblReceivedData.Text = "Deleting File";
if(File.Exists(jobData.localPath + jobData.localName))
File.Delete(jobData.localPath + jobData.localName);
MessageBox.Show("The following error was encountered when attempting to download the file:\n\n" + e.Message + "\n\nThe job for this file will now be removed.");
lblReceivedData.Text = "Deleting Job";
JobManagement.DeleteJob(jobData.url);
MainForm.LoadJobs(false);
nt.KillMe();
this.Close();
this.Dispose();
return;
}
// set nowDownloading in filelist.xml to true
jobData.nowDownloading=true;
if (queryresume)
JobManagement.ModifyJob(jobData, true);
else
JobManagement.ModifyJob(jobData, false);
// is this download resumable. if the filesize is 0 then it's not.
if (filesize == 0) {
cmdPause.Enabled=resumable=false;
// set the filestream position back to zero
fs.Position=0;
lblNotResumable.Visible =true;
}
// if we're down here we must have gotten through OK, start reading the data in chunks of 1KB
lblReceivedData.Text = "Downloading File";
byte[] b=new byte[1024]; // we want to start reading the data in bigger chunks
long totalbytes=fs.Position;
long totalfilesize=filesize + startfrom;
// set up the progress bar. we're setting the Maximum property of the progress bar to 2500 because
// it (in the PDC SDK pre-release) seems to have a problem with large values.
pb.Maximum = 2500;
if (filesize > 0)
pb.Value = (int)(totalbytes / totalfilesize) * pb.Maximum;
// holds the number of bytes read when calling the BinaryStream's Read() method (the 1 is a fudge)
int bytesread=1;
while (bytesread > 0 && !stopdownload) {
bytesread=nt.br.Read(b, 0, b.Length);
fs.Write(b, 0, bytesread);
totalbytes+=bytesread;
lblReceivedData.Text = (totalbytes/1024) + "KB / " + (filesize > 0 ? (totalfilesize / 1024) + "KB" : "unknown");
// can someone explain to me why we need to convert integers to floats before we can perform
// division on them?? (returns zero if I get rid of the conversions. weird)
if (filesize > 0)
pb.Value=(int)((float)totalbytes / (float)totalfilesize * (float)pb.Maximum);
// update the title bar
this.Text = (int)((float)totalbytes / (float)totalfilesize * (float)100) + "% completed of " + jobData.localName;
}
// close the stream objects
fs.Close();
// if we're down here then StopDownload needn't be executed
handledclose=true;
jobData.nowDownloading = false;
// did this download get cut short. If the user hasn't set stopdownload to true and the socket is
// still connected, we'll say that it did.
if (!stopdownload && (totalbytes < filesize + startfrom)) {
MessageBox.Show("Connection to server terminated abnormally. Check your network connection and try again.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
this.Close();
this.Dispose();
nt.KillMe();
return;
}
// either the Stop button was clicked or the download was completed. If this is the case, destroy
// this window and, if we're finished with this download delete the entry for this download in
// filelist.xml
if (closewindow || bytesread==0) {
this.Close();
// if deletefile==true or bytesread==0 then we've finished with the download, so nuke the job
// from filelist.xml
if (deletefile || bytesread==0)
JobManagement.DeleteJob(jobData.url);
else
JobManagement.ModifyJob(jobData, false);
// if we're here because Stop was clicked, the user may have opted to delete the data they'd
// downloaded. If that's the case, we want to delete the file we created.
if (deletefile)
File.Delete(filePath);
this.Dispose();
}
// if the following condition is true (we want to stop the download but not close the window), the
// user has chosen to cancel the download. So let's not confuse them, and change the label on the
// pause button to Resume.
if (stopdownload && !closewindow) {
//statusLabel.Text = statusLabel.Text + " Paused.";
cmdPause.Text = "&Resume";
}
// kill the instance of HttpFunctions (closes the socket connection, network stream and binary reader)
nt.KillMe();
MainForm.LoadJobs(false);
return;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -