diff --git a/CodeStatistics/App.config b/CodeStatistics/App.config new file mode 100644 index 0000000..f0836c8 --- /dev/null +++ b/CodeStatistics/App.config @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="utf-8" ?> +<configuration> + <system.net> + <settings> + <httpWebRequest useUnsafeHeaderParsing="true" /> + </settings> + </system.net> +</configuration> \ No newline at end of file diff --git a/CodeStatistics/CodeStatistics.csproj b/CodeStatistics/CodeStatistics.csproj index d68c133..19ff2ec 100644 --- a/CodeStatistics/CodeStatistics.csproj +++ b/CodeStatistics/CodeStatistics.csproj @@ -53,6 +53,7 @@ <ItemGroup> <Reference Include="System" /> <Reference Include="System.Drawing" /> + <Reference Include="System.Web.Extensions" /> <Reference Include="System.Windows.Forms" /> <Reference Include="WindowsBase" /> </ItemGroup> @@ -154,6 +155,9 @@ <ItemGroup> <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> </ItemGroup> + <ItemGroup> + <None Include="App.config" /> + </ItemGroup> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <!-- To modify your build process, add your task inside one of the targets below and uncomment it. Other similar extension points exist, see Microsoft.Common.targets. diff --git a/CodeStatistics/Forms/GitHubForm.Designer.cs b/CodeStatistics/Forms/GitHubForm.Designer.cs new file mode 100644 index 0000000..67f7322 --- /dev/null +++ b/CodeStatistics/Forms/GitHubForm.Designer.cs @@ -0,0 +1,140 @@ +namespace CodeStatistics.Forms { + partial class GitHubForm { + /// <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.textBoxRepository = new System.Windows.Forms.TextBox(); + this.labelRepository = new System.Windows.Forms.Label(); + this.btnCancel = new System.Windows.Forms.Button(); + this.btnListBranches = new System.Windows.Forms.Button(); + this.labelBranch = new System.Windows.Forms.Label(); + this.listBranches = new System.Windows.Forms.ComboBox(); + this.btnDownload = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // textBoxRepository + // + this.textBoxRepository.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textBoxRepository.Location = new System.Drawing.Point(15, 25); + this.textBoxRepository.Name = "textBoxRepository"; + this.textBoxRepository.Size = new System.Drawing.Size(298, 20); + this.textBoxRepository.TabIndex = 0; + // + // labelRepository + // + this.labelRepository.AutoSize = true; + this.labelRepository.BackColor = System.Drawing.Color.Transparent; + this.labelRepository.Location = new System.Drawing.Point(12, 9); + this.labelRepository.Name = "labelRepository"; + this.labelRepository.Size = new System.Drawing.Size(91, 13); + this.labelRepository.TabIndex = 1; + this.labelRepository.Text = "Repository Name:"; + // + // btnCancel + // + this.btnCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.btnCancel.Location = new System.Drawing.Point(238, 113); + this.btnCancel.Name = "btnCancel"; + this.btnCancel.Size = new System.Drawing.Size(75, 23); + this.btnCancel.TabIndex = 2; + this.btnCancel.Text = "Cancel"; + this.btnCancel.UseVisualStyleBackColor = true; + this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click); + // + // btnListBranches + // + this.btnListBranches.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.btnListBranches.Location = new System.Drawing.Point(139, 113); + this.btnListBranches.Name = "btnListBranches"; + this.btnListBranches.Size = new System.Drawing.Size(93, 23); + this.btnListBranches.TabIndex = 3; + this.btnListBranches.Text = "List Branches"; + this.btnListBranches.UseVisualStyleBackColor = true; + this.btnListBranches.Click += new System.EventHandler(this.btnListBranches_Click); + // + // labelBranch + // + this.labelBranch.AutoSize = true; + this.labelBranch.BackColor = System.Drawing.Color.Transparent; + this.labelBranch.Location = new System.Drawing.Point(12, 57); + this.labelBranch.Name = "labelBranch"; + this.labelBranch.Size = new System.Drawing.Size(44, 13); + this.labelBranch.TabIndex = 4; + this.labelBranch.Text = "Branch:"; + // + // listBranches + // + this.listBranches.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.listBranches.FormattingEnabled = true; + this.listBranches.Location = new System.Drawing.Point(15, 73); + this.listBranches.Name = "listBranches"; + this.listBranches.Size = new System.Drawing.Size(298, 21); + this.listBranches.TabIndex = 6; + // + // btnDownload + // + this.btnDownload.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.btnDownload.Location = new System.Drawing.Point(58, 113); + this.btnDownload.Name = "btnDownload"; + this.btnDownload.Size = new System.Drawing.Size(75, 23); + this.btnDownload.TabIndex = 7; + this.btnDownload.Text = "Download"; + this.btnDownload.UseVisualStyleBackColor = true; + this.btnDownload.Click += new System.EventHandler(this.btnDownload_Click); + // + // GitHubForm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.BackColor = System.Drawing.Color.White; + this.ClientSize = new System.Drawing.Size(325, 148); + this.Controls.Add(this.btnDownload); + this.Controls.Add(this.listBranches); + this.Controls.Add(this.labelBranch); + this.Controls.Add(this.btnListBranches); + this.Controls.Add(this.btnCancel); + this.Controls.Add(this.labelRepository); + this.Controls.Add(this.textBoxRepository); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; + this.MaximizeBox = false; + this.Name = "GitHubForm"; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; + this.Load += new System.EventHandler(this.OnLoad); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.TextBox textBoxRepository; + private System.Windows.Forms.Label labelRepository; + private System.Windows.Forms.Button btnCancel; + private System.Windows.Forms.Button btnListBranches; + private System.Windows.Forms.Label labelBranch; + private System.Windows.Forms.ComboBox listBranches; + private System.Windows.Forms.Button btnDownload; + } +} \ No newline at end of file diff --git a/CodeStatistics/Forms/GitHubForm.cs b/CodeStatistics/Forms/GitHubForm.cs new file mode 100644 index 0000000..9f84fcd --- /dev/null +++ b/CodeStatistics/Forms/GitHubForm.cs @@ -0,0 +1,45 @@ +using CodeStatistics.Input.Methods; +using System; +using System.Windows.Forms; + +namespace CodeStatistics.Forms{ + public partial class GitHubForm : Form{ + public GitHub GitHub { get; private set; } + + public GitHubForm(){ + InitializeComponent(); + } + + private void OnLoad(object sender, EventArgs e){ + listBranches.Items.Add("master"); + listBranches.SelectedIndex = 0; + } + + private void btnDownload_Click(object sender, EventArgs e){ + string[] data = textBoxRepository.Text.Split('/'); + GitHub = new GitHub(data[0],data[1]); + GitHub.Branch = (string)listBranches.SelectedItem; + + DialogResult = DialogResult.OK; + Close(); + } + + private void btnListBranches_Click(object sender, EventArgs e){ + string[] data = textBoxRepository.Text.Split('/'); + GitHub github = new GitHub(data[0],data[1]); + + github.RetrieveBranchList(branches => this.InvokeOnUIThread(() => { + listBranches.Items.Clear(); + + foreach(string branch in branches){ + listBranches.Items.Add(branch); + } + })); + } + + private void btnCancel_Click(object sender, EventArgs e){ + DialogResult = DialogResult.Cancel; + Close(); + } + } +} diff --git a/CodeStatistics/Forms/MainForm.Designer.cs b/CodeStatistics/Forms/MainForm.Designer.cs index 42a3c00..4bdaff6 100644 --- a/CodeStatistics/Forms/MainForm.Designer.cs +++ b/CodeStatistics/Forms/MainForm.Designer.cs @@ -60,6 +60,7 @@ this.btnProjectGitHub.Size = new System.Drawing.Size(312, 38); this.btnProjectGitHub.TabIndex = 1; this.btnProjectGitHub.UseVisualStyleBackColor = false; + this.btnProjectGitHub.Click += new System.EventHandler(this.btnProjectGitHub_Click); // // btnViewSourceCode // diff --git a/CodeStatistics/Forms/MainForm.cs b/CodeStatistics/Forms/MainForm.cs index 18451b0..91492bc 100644 --- a/CodeStatistics/Forms/MainForm.cs +++ b/CodeStatistics/Forms/MainForm.cs @@ -56,6 +56,16 @@ namespace CodeStatistics.Forms{ } } + private void btnProjectGitHub_Click(object sender, EventArgs e){ + GitHubForm form = new GitHubForm(); + + if (form.ShowDialog() == DialogResult.OK){ + InputMethod = form.GitHub; + DialogResult = DialogResult.OK; + Close(); + } + } + private void btnViewSourceCode_Click(object sender, EventArgs e){ Process.Start("https://github.com/chylex/Code-Statistics"); } diff --git a/CodeStatistics/Input/Methods/GitHub.cs b/CodeStatistics/Input/Methods/GitHub.cs index ae6b409..fe04c47 100644 --- a/CodeStatistics/Input/Methods/GitHub.cs +++ b/CodeStatistics/Input/Methods/GitHub.cs @@ -1,18 +1,28 @@ using System; +using System.Linq; +using System.Collections.Generic; using System.ComponentModel; using System.Net; +using System.Net.NetworkInformation; +using System.Web.Script.Serialization; +using CodeStatistics.Forms; namespace CodeStatistics.Input.Methods{ - public class GitHub : IDisposable{ + public class GitHub : IInputMethod, IDisposable{ public enum DownloadStatus{ NoInternet, NoConnection, Started } + public delegate void BranchListRetrieved(IEnumerable<string> branches); + private readonly string target; - private WebClient downloader; + private WebClient dlBranches, dlRepo; + + public string Branch = "master"; public string RepositoryName { get { return target; } } - public string ZipUrl { get { return "https://github.com/"+target+"/zipball/master"; } } + public string BranchesUrl { get { return "https://api.github.com/repos/"+target+"/branches"; } } + public string ZipUrl { get { return "https://github.com/"+target+"/zipball/"+Branch; } } public event DownloadProgressChangedEventHandler DownloadProgressChanged; public event AsyncCompletedEventHandler DownloadFinished; @@ -21,18 +31,53 @@ namespace CodeStatistics.Input.Methods{ this.target = username+"/"+repository; } - public DownloadStatus DownloadRepositoryZip(string targetFile){ - if (!System.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable()){ + public DownloadStatus RetrieveBranchList(BranchListRetrieved onRetrieved){ + if (dlBranches != null)Reset(); + + if (!NetworkInterface.GetIsNetworkAvailable()){ return DownloadStatus.NoInternet; } - downloader = new WebClient(); + dlBranches = CreateWebClient(); - if (DownloadProgressChanged != null)downloader.DownloadProgressChanged += DownloadProgressChanged; - if (DownloadFinished != null)downloader.DownloadFileCompleted += DownloadFinished; + dlBranches.DownloadStringCompleted += (sender, args) => { + if (args.Cancelled || args.Error != null){ + onRetrieved(null); + return; + } + + List<string> branches = new List<string>(2); + + foreach(object entry in (object[])new JavaScriptSerializer().DeserializeObject(args.Result)){ + branches.Add((string)((Dictionary<string,object>)entry)["name"]); + } + + if (branches.Remove("master"))onRetrieved(Enumerable.Repeat("master",1).Concat(branches)); + else onRetrieved(branches); + }; try{ - downloader.DownloadFileAsync(new Uri(ZipUrl),targetFile); + dlBranches.DownloadStringAsync(new Uri(BranchesUrl)); + return DownloadStatus.Started; + }catch(WebException){ + return DownloadStatus.NoConnection; + } + } + + public DownloadStatus DownloadRepositoryZip(string targetFile){ + if (dlRepo != null)Reset(); + + if (!NetworkInterface.GetIsNetworkAvailable()){ + return DownloadStatus.NoInternet; + } + + dlRepo = CreateWebClient(); + + if (DownloadProgressChanged != null)dlRepo.DownloadProgressChanged += DownloadProgressChanged; + if (DownloadFinished != null)dlRepo.DownloadFileCompleted += DownloadFinished; + + try{ + dlRepo.DownloadFileAsync(new Uri(ZipUrl),targetFile); return DownloadStatus.Started; }catch(WebException){ return DownloadStatus.NoConnection; @@ -40,11 +85,55 @@ namespace CodeStatistics.Input.Methods{ } public void Cancel(){ - if (downloader != null)downloader.CancelAsync(); + if (dlBranches != null)dlBranches.CancelAsync(); + if (dlRepo != null)dlRepo.CancelAsync(); } public void Dispose(){ - if (downloader != null)downloader.Dispose(); + if (dlBranches != null)dlBranches.Dispose(); + if (dlRepo != null)dlRepo.Dispose(); + } + + private void Reset(){ + Cancel(); + Dispose(); + } + + public void BeginProcess(ProjectLoadForm.UpdateCallbacks callbacks){ // TODO + DownloadProgressChanged += (sender, args) => { + callbacks.UpdateProgress(args.ProgressPercentage); + callbacks.UpdateDataLabel(args.TotalBytesToReceive/1024 == 0 ? (args.BytesReceived/1024)+" kB" : (args.BytesReceived/1024)+" / "+(args.TotalBytesToReceive/1024)+" kB"); + }; + + DownloadFinished += (sender, args) => { + callbacks.UpdateInfoLabel("Extracting repository..."); + // TODO extraction + }; + + switch(DownloadRepositoryZip("tmp.zip")){ + case DownloadStatus.Started: + callbacks.UpdateInfoLabel("Downloading repository..."); + break; + + case DownloadStatus.NoInternet: + callbacks.UpdateInfoLabel("No internet connection."); + break; + + case DownloadStatus.NoConnection: + callbacks.UpdateInfoLabel("Could not establish connection with GitHub."); + break; + } + } + + public void CancelProcess(Action onCancelFinish){ + Reset(); + onCancelFinish(); + } + + private static WebClient CreateWebClient(){ + WebClient client = new WebClient(); + client.Headers.Add("User-Agent","CodeStatistics"); + return client; } } }