├── .gitattributes ├── .gitignore ├── .gitmodules ├── Installer ├── Bundle.wxs └── Installer.wixproj ├── README.md ├── Redmine.Client ├── AboutBox.Designer.cs ├── AboutBox.cs ├── AboutBox.resx ├── AttachmentForm.Designer.cs ├── AttachmentForm.cs ├── AttachmentForm.resx ├── BgWork.cs ├── BgWorker.cs ├── ClientExtensionMethods.cs ├── CommitForm.Designer.cs ├── CommitForm.cs ├── CommitForm.resx ├── EditEnumForm.Designer.cs ├── EditEnumForm.cs ├── EditEnumForm.resx ├── EditEnumListForm.Designer.cs ├── EditEnumListForm.cs ├── EditEnumListForm.resx ├── Enumerations.cs ├── IssueForm.Designer.cs ├── IssueForm.cs ├── IssueForm.resx ├── IssueFormData.cs ├── IssueGridSelectColumns.Designer.cs ├── IssueGridSelectColumns.cs ├── IssueGridSelectColumns.resx ├── Languages │ ├── Lang.Designer.cs │ ├── Lang.cs-CZ.resx │ ├── Lang.de.resx │ ├── Lang.es-MX.resx │ ├── Lang.fr.resx │ ├── Lang.gl.resx │ ├── Lang.nl.resx │ ├── Lang.pl.resx │ ├── Lang.pt-BR.resx │ ├── Lang.resx │ ├── Lang.ru.resx │ ├── Lang.zh-CN.resx │ └── LangTools.cs ├── MainFormData.cs ├── OpenSpecificIssueForm.Designer.cs ├── OpenSpecificIssueForm.cs ├── OpenSpecificIssueForm.resx ├── Program.cs ├── ProjectMember.cs ├── Properties │ ├── AssemblyInfo.cs │ ├── Resources.resx │ ├── Resources1.Designer.cs │ ├── Settings.Designer.cs │ ├── Settings.cs │ ├── Settings.settings │ └── app.config ├── Redmine.Client.csproj ├── RedmineClientForm.Designer.cs ├── RedmineClientForm.cs ├── RedmineClientForm.resx ├── SettingsForm.Designer.cs ├── SettingsForm.cs ├── SettingsForm.resx ├── TimeEntriesForm.Designer.cs ├── TimeEntriesForm.cs ├── TimeEntriesForm.resx ├── TimeEntryForm.Designer.cs ├── TimeEntryForm.cs ├── TimeEntryForm.resx ├── UpdateIssueNoteForm.Designer.cs ├── UpdateIssueNoteForm.cs ├── UpdateIssueNoteForm.resx ├── Utility.cs ├── app.config └── res │ ├── aboutclock.png │ ├── clock-installer.png │ ├── clock-transparant.png │ ├── clock.ico │ └── clock.png ├── RedmineClient.sln └── Setup ├── Banner.bmp ├── Dialog.bmp ├── License.RedmineClient.rtf ├── Product.wxs └── Setup.wixproj /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | 3 | ### c# and c++ stuff 4 | *.cs text 5 | *.c text 6 | *.cpp text 7 | *.h text 8 | *.hpp text 9 | *.dsp text eol=crlf 10 | *.dsw text eol=crlf 11 | *.vcprops text eol=crlf 12 | *.vcproj text eol=crlf 13 | *.vcxproj text eol=crlf 14 | *.props text eol=crlf 15 | *.sln text eol=crlf 16 | *.vcxproj.filters text eol=crlf 17 | *.rc text=auto 18 | *.rc2 text=auto 19 | resource.h text=auto 20 | 21 | ### Other 22 | *.ps1 text eol=crlf 23 | *.bat text eol=crlf 24 | *.reg text 25 | Makefile text 26 | *.sh text 27 | *.txt text 28 | *.bmp binary 29 | *.png binary 30 | *.jpg binary 31 | *.gif binary 32 | *.xml text 33 | *.wsdl text 34 | *.html text 35 | *.htm text 36 | *.css text 37 | *.js text 38 | *.mib text 39 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /Redmine.Api 2 | sys$command 3 | bin 4 | obj 5 | *.suo -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "Redmine.Api"] 2 | path = Redmine.Api 3 | url = https://github.com/zapadi/redmine-net-api.git 4 | -------------------------------------------------------------------------------- /Installer/Bundle.wxs: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /Installer/Installer.wixproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | x86 6 | 3.6 7 | {de8a1716-dea3-4cea-83e5-d24d94519b45} 8 | 2.0 9 | Installer 10 | Bundle 11 | $(MSBuildExtensionsPath32)\Microsoft\WiX\v3.x\Wix.targets 12 | $(MSBuildExtensionsPath)\Microsoft\WiX\v3.x\Wix.targets 13 | OnBuildSuccess 14 | 15 | 16 | bin\$(Configuration)\ 17 | obj\$(Configuration)\ 18 | Debug 19 | 20 | 21 | bin\$(Configuration)\ 22 | obj\$(Configuration)\ 23 | 24 | 25 | 26 | 27 | 28 | 29 | $(WixExtDir)\WixNetFxExtension.dll 30 | WixNetFxExtension 31 | 32 | 33 | $(WixExtDir)\WixBalExtension.dll 34 | WixBalExtension 35 | 36 | 37 | 38 | 39 | Setup 40 | {cae8e32c-d717-4ed3-a795-c5d10fdbe64e} 41 | True 42 | True 43 | Binaries;Content;Satellites 44 | INSTALLFOLDER 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Redmine Desktop Client 2 | Desktop tool for reporting time spent on issues in Redmine project management system. 3 | 4 | You can download it, report bugs, get the source or post feature requests on https://github.com/TheMagician1/redmine-desktop-client 5 | -------------------------------------------------------------------------------- /Redmine.Client/AboutBox.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | using System.Windows.Forms; 4 | 5 | namespace Redmine.Client 6 | { 7 | partial class AboutBox : Form 8 | { 9 | public AboutBox() 10 | { 11 | InitializeComponent(); 12 | //this.Text = String.Format("About {0} {0}", AssemblyTitle); 13 | //this.labelProductName.Text = AssemblyProduct; 14 | this.labelVersion.Text = String.Format("Version {0}", AssemblyVersion); 15 | //this.labelCopyright.Text = AssemblyCopyright; 16 | //this.labelCompanyName.Text = AssemblyCompany; 17 | //this.textBoxDescription.Text = AssemblyDescription; 18 | } 19 | 20 | #region Assembly Attribute Accessors 21 | 22 | public string AssemblyTitle 23 | { 24 | get 25 | { 26 | object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyTitleAttribute), false); 27 | if (attributes.Length > 0) 28 | { 29 | AssemblyTitleAttribute titleAttribute = (AssemblyTitleAttribute)attributes[0]; 30 | if (titleAttribute.Title != "") 31 | { 32 | return titleAttribute.Title; 33 | } 34 | } 35 | return System.IO.Path.GetFileNameWithoutExtension(Assembly.GetExecutingAssembly().CodeBase); 36 | } 37 | } 38 | 39 | public string AssemblyVersion 40 | { 41 | get 42 | { 43 | return Assembly.GetExecutingAssembly().GetName().Version.ToString(); 44 | } 45 | } 46 | 47 | public string AssemblyDescription 48 | { 49 | get 50 | { 51 | object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyDescriptionAttribute), false); 52 | if (attributes.Length == 0) 53 | { 54 | return ""; 55 | } 56 | return ((AssemblyDescriptionAttribute)attributes[0]).Description; 57 | } 58 | } 59 | 60 | public string AssemblyProduct 61 | { 62 | get 63 | { 64 | object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyProductAttribute), false); 65 | if (attributes.Length == 0) 66 | { 67 | return ""; 68 | } 69 | return ((AssemblyProductAttribute)attributes[0]).Product; 70 | } 71 | } 72 | 73 | public string AssemblyCopyright 74 | { 75 | get 76 | { 77 | object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyCopyrightAttribute), false); 78 | if (attributes.Length == 0) 79 | { 80 | return ""; 81 | } 82 | return ((AssemblyCopyrightAttribute)attributes[0]).Copyright; 83 | } 84 | } 85 | 86 | public string AssemblyCompany 87 | { 88 | get 89 | { 90 | object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyCompanyAttribute), false); 91 | if (attributes.Length == 0) 92 | { 93 | return ""; 94 | } 95 | return ((AssemblyCompanyAttribute)attributes[0]).Company; 96 | } 97 | } 98 | #endregion 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /Redmine.Client/AboutBox.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | Copyright © Pavel Kalian 2009, All rights reserved 122 | Copyright © Bas van Leeuwen 2012-2013 123 | 124 | Other Contributor(s): Johan 't Hart 125 | 126 | Translators: 127 | Blackman82 (Czech); jgoetze && fabismailer (German); rafaelff1 (Portugese (Brazil)); MademoiselleGeek && xtinsive (French); mbouzada (Galician); legal90 (Russian); milek (Polish); gusanito (Spanish (Mexico)); mguo163 (Chinese (China)) 128 | 129 | 130 | Redmine Desktop Client 131 | ========= 132 | 133 | Desktop tool for reporting time spent on issues in Redmine project management system. 134 | 135 | You can download it, report bugs, get the source or post feature requests on http://code.google.com/p/redmine-desktop-client 136 | 137 | You are free to use this code as much as you wish, but if you make any improvemens, please share them with the community. 138 | 139 | Icons from the excellent Nuvola theme drawn by David Vignoni. 140 | 141 | Copyright (c) 2009, Pavel Kalian 142 | Copyright (c) 2012, Bas van Leeuwen 143 | Other Contributors: Johan 't Hart 144 | All rights reserved. 145 | 146 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 147 | 148 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 149 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 150 | * Neither the name of the author nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 151 | 152 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 153 | 154 | -------------------------------------------------------------------------------- /Redmine.Client/AttachmentForm.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace Redmine.Client 2 | { 3 | partial class AttachmentForm 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.openFileDialog = new System.Windows.Forms.OpenFileDialog(); 32 | this.labelAttachmentDescription = new System.Windows.Forms.Label(); 33 | this.textBoxDescription = new System.Windows.Forms.TextBox(); 34 | this.BtnOKButton = new System.Windows.Forms.Button(); 35 | this.BtnCancelButton = new System.Windows.Forms.Button(); 36 | this.textBoxAttachmentFilePath = new System.Windows.Forms.TextBox(); 37 | this.labelSelectAttachment = new System.Windows.Forms.Label(); 38 | this.BtnBrowseButton = new System.Windows.Forms.Button(); 39 | this.SuspendLayout(); 40 | // 41 | // openFileDialog 42 | // 43 | this.openFileDialog.FileName = "*.*"; 44 | // 45 | // labelAttachmentDescription 46 | // 47 | this.labelAttachmentDescription.AutoSize = true; 48 | this.labelAttachmentDescription.Location = new System.Drawing.Point(9, 57); 49 | this.labelAttachmentDescription.Name = "labelAttachmentDescription"; 50 | this.labelAttachmentDescription.Size = new System.Drawing.Size(60, 13); 51 | this.labelAttachmentDescription.TabIndex = 17; 52 | this.labelAttachmentDescription.Text = "Description"; 53 | // 54 | // textBoxDescription 55 | // 56 | this.textBoxDescription.Location = new System.Drawing.Point(12, 75); 57 | this.textBoxDescription.Name = "textBoxDescription"; 58 | this.textBoxDescription.Size = new System.Drawing.Size(366, 20); 59 | this.textBoxDescription.TabIndex = 16; 60 | // 61 | // BtnOKButton 62 | // 63 | this.BtnOKButton.Location = new System.Drawing.Point(125, 101); 64 | this.BtnOKButton.Margin = new System.Windows.Forms.Padding(2); 65 | this.BtnOKButton.Name = "BtnOKButton"; 66 | this.BtnOKButton.Size = new System.Drawing.Size(68, 24); 67 | this.BtnOKButton.TabIndex = 14; 68 | this.BtnOKButton.Text = "OK"; 69 | this.BtnOKButton.UseVisualStyleBackColor = true; 70 | this.BtnOKButton.Click += new System.EventHandler(this.BtnOKButton_Click); 71 | // 72 | // BtnCancelButton 73 | // 74 | this.BtnCancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel; 75 | this.BtnCancelButton.Location = new System.Drawing.Point(197, 101); 76 | this.BtnCancelButton.Margin = new System.Windows.Forms.Padding(2); 77 | this.BtnCancelButton.Name = "BtnCancelButton"; 78 | this.BtnCancelButton.Size = new System.Drawing.Size(68, 24); 79 | this.BtnCancelButton.TabIndex = 15; 80 | this.BtnCancelButton.Text = "Cancel"; 81 | this.BtnCancelButton.UseVisualStyleBackColor = true; 82 | // 83 | // textBoxAttachmentFilePath 84 | // 85 | this.textBoxAttachmentFilePath.Location = new System.Drawing.Point(12, 32); 86 | this.textBoxAttachmentFilePath.Name = "textBoxAttachmentFilePath"; 87 | this.textBoxAttachmentFilePath.Size = new System.Drawing.Size(293, 20); 88 | this.textBoxAttachmentFilePath.TabIndex = 16; 89 | // 90 | // labelSelectAttachment 91 | // 92 | this.labelSelectAttachment.AutoSize = true; 93 | this.labelSelectAttachment.Location = new System.Drawing.Point(12, 14); 94 | this.labelSelectAttachment.Name = "labelSelectAttachment"; 95 | this.labelSelectAttachment.Size = new System.Drawing.Size(80, 13); 96 | this.labelSelectAttachment.TabIndex = 17; 97 | this.labelSelectAttachment.Text = "Attachment File"; 98 | // 99 | // BtnBrowseButton 100 | // 101 | this.BtnBrowseButton.Location = new System.Drawing.Point(310, 29); 102 | this.BtnBrowseButton.Margin = new System.Windows.Forms.Padding(2); 103 | this.BtnBrowseButton.Name = "BtnBrowseButton"; 104 | this.BtnBrowseButton.Size = new System.Drawing.Size(68, 24); 105 | this.BtnBrowseButton.TabIndex = 15; 106 | this.BtnBrowseButton.Text = "Browse"; 107 | this.BtnBrowseButton.UseVisualStyleBackColor = true; 108 | this.BtnBrowseButton.Click += new System.EventHandler(this.buttonBrowse_Click); 109 | // 110 | // AttachmentForm 111 | // 112 | this.AcceptButton = this.BtnOKButton; 113 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 114 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 115 | this.CancelButton = this.BtnCancelButton; 116 | this.ClientSize = new System.Drawing.Size(390, 136); 117 | this.Controls.Add(this.labelSelectAttachment); 118 | this.Controls.Add(this.labelAttachmentDescription); 119 | this.Controls.Add(this.textBoxAttachmentFilePath); 120 | this.Controls.Add(this.textBoxDescription); 121 | this.Controls.Add(this.BtnOKButton); 122 | this.Controls.Add(this.BtnBrowseButton); 123 | this.Controls.Add(this.BtnCancelButton); 124 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; 125 | this.Name = "AttachmentForm"; 126 | this.ShowIcon = false; 127 | this.ShowInTaskbar = false; 128 | this.Text = "AttachmentForm"; 129 | this.ResumeLayout(false); 130 | this.PerformLayout(); 131 | 132 | } 133 | 134 | #endregion 135 | 136 | private System.Windows.Forms.OpenFileDialog openFileDialog; 137 | private System.Windows.Forms.Label labelAttachmentDescription; 138 | private System.Windows.Forms.TextBox textBoxDescription; 139 | private System.Windows.Forms.Button BtnOKButton; 140 | private System.Windows.Forms.Button BtnCancelButton; 141 | private System.Windows.Forms.TextBox textBoxAttachmentFilePath; 142 | private System.Windows.Forms.Label labelSelectAttachment; 143 | private System.Windows.Forms.Button BtnBrowseButton; 144 | } 145 | } -------------------------------------------------------------------------------- /Redmine.Client/AttachmentForm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Drawing; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Windows.Forms; 9 | using Redmine.Net.Api.Types; 10 | using Redmine.Client.Languages; 11 | using System.IO; 12 | using Microsoft.Win32; 13 | 14 | namespace Redmine.Client 15 | { 16 | public partial class AttachmentForm : Form 17 | { 18 | private DialogType type; 19 | private Issue issue; 20 | public Attachment NewAttachment { get; private set; } 21 | 22 | public AttachmentForm(Issue issue, DialogType type, string path) 23 | { 24 | InitializeComponent(); 25 | this.type = type; 26 | this.issue = issue; 27 | textBoxAttachmentFilePath.Text = path; 28 | LangTools.UpdateControlsForLanguage(this.Controls); 29 | this.Text = String.Format(Lang.DlgAttachmentTitle, issue.Id, issue.Subject); 30 | } 31 | 32 | private void buttonBrowse_Click(object sender, EventArgs e) 33 | { 34 | openFileDialog.InitialDirectory = textBoxAttachmentFilePath.Text; 35 | if (openFileDialog.ShowDialog(this) == DialogResult.OK) 36 | textBoxAttachmentFilePath.Text = openFileDialog.FileName; 37 | } 38 | 39 | private void BtnOKButton_Click(object sender, EventArgs e) 40 | { 41 | try 42 | { 43 | if (type == DialogType.Edit) 44 | { 45 | byte[] file = File.ReadAllBytes(textBoxAttachmentFilePath.Text); 46 | Upload uploadedFile = RedmineClientForm.redmine.UploadFile(file); 47 | uploadedFile.FileName = Path.GetFileName(textBoxAttachmentFilePath.Text); 48 | uploadedFile.Description = textBoxDescription.Text; 49 | uploadedFile.ContentType = GetMimeType(Path.GetExtension(textBoxAttachmentFilePath.Text)); 50 | issue.Uploads = new List(); 51 | issue.Uploads.Add(uploadedFile); 52 | RedmineClientForm.redmine.UpdateObject(issue.Id.ToString(), issue); 53 | } 54 | else 55 | { 56 | NewAttachment = new Attachment 57 | { 58 | ContentUrl = textBoxAttachmentFilePath.Text, 59 | Description = textBoxDescription.Text, 60 | FileName = Path.GetFileName(textBoxAttachmentFilePath.Text), 61 | ContentType = GetMimeType(Path.GetExtension(textBoxAttachmentFilePath.Text)), 62 | FileSize = (int)new FileInfo(textBoxAttachmentFilePath.Text).Length, 63 | Author = new IdentifiableName { Id = RedmineClientForm.Instance.CurrentUser.Id, Name = RedmineClientForm.Instance.CurrentUser.CompleteName() } 64 | }; 65 | } 66 | DialogResult = DialogResult.OK; 67 | this.Close(); 68 | } 69 | catch (Exception ex) 70 | { 71 | MessageBox.Show(String.Format(Lang.Error_Exception, ex.Message), Lang.Error, MessageBoxButtons.OK, MessageBoxIcon.Error); 72 | } 73 | } 74 | 75 | 76 | public static string GetMimeType(string extension) 77 | { 78 | string mimeType = "application/unknown"; 79 | 80 | RegistryKey regKey = Registry.ClassesRoot.OpenSubKey(extension.ToLower()); 81 | 82 | if(regKey != null) 83 | { 84 | object contentType = regKey.GetValue("Content Type"); 85 | 86 | if(contentType != null) 87 | mimeType = contentType.ToString(); 88 | } 89 | 90 | return mimeType; 91 | } 92 | 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /Redmine.Client/AttachmentForm.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | 17, 17 122 | 123 | -------------------------------------------------------------------------------- /Redmine.Client/BgWork.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace Redmine.Client 7 | { 8 | /// 9 | /// Class for storing asynchronous functions 10 | /// 11 | public class BgWork 12 | { 13 | /// 14 | /// Constructor of Background work 15 | /// 16 | /// a descriptive name for the job 17 | /// the actual function to call 18 | public BgWork(String name, RunAsync work) 19 | { 20 | m_name = name; 21 | m_work = work; 22 | } 23 | public String m_name; 24 | public RunAsync m_work; 25 | }; 26 | } 27 | -------------------------------------------------------------------------------- /Redmine.Client/BgWorker.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Windows.Forms; 6 | 7 | namespace Redmine.Client 8 | { 9 | public delegate void OnDone(); 10 | public delegate OnDone RunAsync(); 11 | 12 | public class BgWorker : Form 13 | { 14 | private System.ComponentModel.BackgroundWorker worker = new System.ComponentModel.BackgroundWorker(); 15 | Queue m_WorkQueue = new Queue(); 16 | public BgWorker() 17 | { 18 | this.worker.DoWork += new System.ComponentModel.DoWorkEventHandler(this.worker_DoWork); 19 | this.worker.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(this.worker_Complete); 20 | } 21 | /// 22 | /// Add a new background job 23 | /// 24 | /// The name used to display in the statusbar when executing this item 25 | /// The function to execute in the background 26 | public void AddBgWork(String name, RunAsync work) 27 | { 28 | m_WorkQueue.Enqueue(new BgWork(name, work)); 29 | TriggerWork(); 30 | } 31 | 32 | /// 33 | /// Start the background worker to process the workqueue 34 | /// 35 | /// Even if the worker is already started, start the next item 36 | private void TriggerWork(bool bForce = false) 37 | { 38 | if (m_WorkQueue.Count == 0) 39 | return; //No work 40 | if (!bForce && m_WorkQueue.Count != 1) 41 | return; //Already busy... 42 | 43 | worker.RunWorkerAsync(m_WorkQueue.Peek().m_work); 44 | WorkTriggered(m_WorkQueue.Peek()); 45 | } 46 | 47 | virtual protected void WorkTriggered(BgWork CurrentWork) {} 48 | 49 | /// 50 | /// Execute the background function 51 | /// 52 | /// 53 | /// 54 | private void worker_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e) 55 | { 56 | if (e.Argument != null) 57 | e.Result = ((RunAsync)e.Argument)(); 58 | } 59 | 60 | /// 61 | /// Current Backgroundwork is complete. Start next item. 62 | /// 63 | /// 64 | /// 65 | private void worker_Complete(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e) 66 | { 67 | if (e.Result != null) 68 | ((OnDone)e.Result)(); 69 | m_WorkQueue.Dequeue(); 70 | WorkTriggered(null); 71 | TriggerWork(true); 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /Redmine.Client/ClientExtensionMethods.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.IO; 6 | using System.Xml; 7 | using System.Xml.Serialization; 8 | using Redmine.Net.Api; 9 | using Redmine.Net.Api.Types; 10 | using System.Collections.Specialized; 11 | 12 | namespace Redmine.Client 13 | { 14 | public static class ClientExtensionMethods 15 | { 16 | public static void WriteCollectionAsElement(this XmlWriter writer, IList list, string listname) where T : class 17 | { 18 | var serializer = new XmlSerializer(typeof(T)); 19 | writer.WriteStartElement(listname); 20 | foreach (T element in list) 21 | { 22 | serializer.Serialize(writer, element); 23 | } 24 | writer.WriteEndElement(); 25 | } 26 | 27 | public static string CompleteName(this User user) 28 | { 29 | string completeName = ""; 30 | if (!String.IsNullOrEmpty(user.FirstName)) 31 | completeName += user.FirstName; 32 | if (!String.IsNullOrEmpty(user.LastName)) 33 | { 34 | if (!String.IsNullOrEmpty(completeName)) 35 | completeName += " "; 36 | completeName += user.LastName; 37 | } 38 | return completeName; 39 | } 40 | 41 | public static String ToByteString(this long byteCount) 42 | { 43 | string[] suf = { "B", "KB", "MB", "GB", "TB", "PB", "EB" }; //Longs run out around EB 44 | if (byteCount == 0) 45 | return "0" + suf[0]; 46 | long bytes = Math.Abs(byteCount); 47 | int place = Convert.ToInt32(Math.Floor(Math.Log(bytes, 1024))); 48 | double num = Math.Round(bytes / Math.Pow(1024, place), 1); 49 | return (Math.Sign(byteCount) * num).ToString() + suf[place]; 50 | } 51 | 52 | public static String ToByteString(this int byteCount) 53 | { 54 | long bytes = byteCount; 55 | return bytes.ToByteString(); 56 | } 57 | 58 | public static void MoveControl(this System.Windows.Forms.Control control, int diffx, int diffy) 59 | { 60 | System.Drawing.Point loc = control.Location; 61 | loc.X += diffx; 62 | loc.Y += diffy; 63 | control.Location = loc; 64 | } 65 | 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /Redmine.Client/CommitForm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Drawing; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Windows.Forms; 9 | using Redmine.Net.Api.Types; 10 | using Redmine.Client.Languages; 11 | 12 | namespace Redmine.Client 13 | { 14 | public partial class CommitForm : Form 15 | { 16 | public Issue issue; 17 | public int ticks = 0; 18 | public string Comment; 19 | public int activityId = 0; 20 | public DateTime spentOn; 21 | public bool closeIssue = false; 22 | 23 | public CommitForm(Issue issue, int ticks, string Comment, int activityId, DateTime spentOn) 24 | { 25 | InitializeComponent(); 26 | LangTools.UpdateControlsForLanguage(this.Controls); 27 | Text = Lang.CommitConfirmQuestion; 28 | 29 | this.issue = issue; 30 | this.ticks = ticks; 31 | this.Comment = Comment; 32 | this.activityId = activityId; 33 | this.spentOn = spentOn; 34 | 35 | labelProjectContent.Text = issue.Project.Name; 36 | labelIssueContent.Text = String.Format("({0}) {1}", issue.Id, issue.Subject); 37 | if (labelIssueContent.Size.Width > Size.Width - labelIssueContent.Location.X - 15) 38 | this.Size = new Size(labelIssueContent.Location.X + labelIssueContent.Size.Width + 15, this.Size.Height); 39 | 40 | ComboBoxActivity.DataSource = Enumerations.Activities; 41 | ComboBoxActivity.DisplayMember = "Name"; 42 | ComboBoxActivity.ValueMember = "Id"; 43 | ComboBoxActivity.SelectedValue = activityId; 44 | 45 | labelTimeContent.Text = String.Format("{0:0.##}", (double)ticks / 3600); 46 | labelDateSpentContent.Text = spentOn.ToString(Lang.Culture.DateTimeFormat.ShortDatePattern); 47 | 48 | TextBoxComment.Text = Comment; 49 | 50 | if (RedmineClientForm.RedmineVersion < ApiVersion.V13x) 51 | { 52 | CheckBoxClosesIssue.Enabled = false; 53 | CheckBoxClosesIssue.Visible = false; 54 | } 55 | } 56 | 57 | private void BtnCommitButton_Click(object sender, EventArgs e) 58 | { 59 | Comment = TextBoxComment.Text; 60 | activityId = ((Enumerations.EnumerationItem)ComboBoxActivity.SelectedItem).Id; 61 | closeIssue = CheckBoxClosesIssue.Checked; 62 | DialogResult = DialogResult.OK; 63 | Close(); 64 | } 65 | 66 | private void BtnCancelButton_Click(object sender, EventArgs e) 67 | { 68 | if (TextBoxComment.Text != Comment) 69 | { 70 | switch (MessageBox.Show(String.Format(Lang.CommitCancelSaveCommentText, Environment.NewLine), Lang.CommitCancelSaveCommentQuestion, MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question)) 71 | { 72 | case DialogResult.Cancel: 73 | this.DialogResult = DialogResult.None; 74 | return; 75 | case DialogResult.Yes: 76 | Comment = TextBoxComment.Text; 77 | break; 78 | } 79 | } 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /Redmine.Client/CommitForm.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /Redmine.Client/EditEnumForm.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace Redmine.Client 2 | { 3 | partial class EditEnumForm 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.BtnOKButton = new System.Windows.Forms.Button(); 32 | this.BtnCancelButton = new System.Windows.Forms.Button(); 33 | this.labelEnumId = new System.Windows.Forms.Label(); 34 | this.EnumNameTextBox = new System.Windows.Forms.TextBox(); 35 | this.EnumIdTextBox = new System.Windows.Forms.MaskedTextBox(); 36 | this.labelEnumName = new System.Windows.Forms.Label(); 37 | this.EnumIsDefaultCheckBox = new System.Windows.Forms.CheckBox(); 38 | this.labelEnumIsDefault = new System.Windows.Forms.Label(); 39 | this.SuspendLayout(); 40 | // 41 | // BtnOKButton 42 | // 43 | this.BtnOKButton.Location = new System.Drawing.Point(141, 54); 44 | this.BtnOKButton.Margin = new System.Windows.Forms.Padding(2); 45 | this.BtnOKButton.Name = "BtnOKButton"; 46 | this.BtnOKButton.Size = new System.Drawing.Size(68, 24); 47 | this.BtnOKButton.TabIndex = 4; 48 | this.BtnOKButton.Text = "OK"; 49 | this.BtnOKButton.UseVisualStyleBackColor = true; 50 | this.BtnOKButton.Click += new System.EventHandler(this.BtnOKButton_Click); 51 | // 52 | // BtnCancelButton 53 | // 54 | this.BtnCancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel; 55 | this.BtnCancelButton.Location = new System.Drawing.Point(213, 54); 56 | this.BtnCancelButton.Margin = new System.Windows.Forms.Padding(2); 57 | this.BtnCancelButton.Name = "BtnCancelButton"; 58 | this.BtnCancelButton.Size = new System.Drawing.Size(68, 24); 59 | this.BtnCancelButton.TabIndex = 5; 60 | this.BtnCancelButton.Text = "Cancel"; 61 | this.BtnCancelButton.UseVisualStyleBackColor = true; 62 | // 63 | // labelEnumId 64 | // 65 | this.labelEnumId.AutoSize = true; 66 | this.labelEnumId.Location = new System.Drawing.Point(9, 13); 67 | this.labelEnumId.Name = "labelEnumId"; 68 | this.labelEnumId.Size = new System.Drawing.Size(16, 13); 69 | this.labelEnumId.TabIndex = 0; 70 | this.labelEnumId.Text = "Id"; 71 | // 72 | // EnumNameTextBox 73 | // 74 | this.EnumNameTextBox.Location = new System.Drawing.Point(45, 29); 75 | this.EnumNameTextBox.Name = "EnumNameTextBox"; 76 | this.EnumNameTextBox.Size = new System.Drawing.Size(235, 20); 77 | this.EnumNameTextBox.TabIndex = 3; 78 | // 79 | // EnumIdTextBox 80 | // 81 | this.EnumIdTextBox.Location = new System.Drawing.Point(12, 29); 82 | this.EnumIdTextBox.Mask = "99"; 83 | this.EnumIdTextBox.Name = "EnumIdTextBox"; 84 | this.EnumIdTextBox.Size = new System.Drawing.Size(27, 20); 85 | this.EnumIdTextBox.TabIndex = 1; 86 | // 87 | // labelEnumName 88 | // 89 | this.labelEnumName.AutoSize = true; 90 | this.labelEnumName.Location = new System.Drawing.Point(42, 13); 91 | this.labelEnumName.Name = "labelEnumName"; 92 | this.labelEnumName.Size = new System.Drawing.Size(35, 13); 93 | this.labelEnumName.TabIndex = 2; 94 | this.labelEnumName.Text = "Name"; 95 | // 96 | // EnumIsDefaultCheckBox 97 | // 98 | this.EnumIsDefaultCheckBox.AutoSize = true; 99 | this.EnumIsDefaultCheckBox.Location = new System.Drawing.Point(295, 37); 100 | this.EnumIsDefaultCheckBox.Name = "EnumIsDefaultCheckBox"; 101 | this.EnumIsDefaultCheckBox.Size = new System.Drawing.Size(15, 14); 102 | this.EnumIsDefaultCheckBox.TabIndex = 6; 103 | this.EnumIsDefaultCheckBox.UseVisualStyleBackColor = true; 104 | // 105 | // labelEnumIsDefault 106 | // 107 | this.labelEnumIsDefault.AutoSize = true; 108 | this.labelEnumIsDefault.Location = new System.Drawing.Point(287, 13); 109 | this.labelEnumIsDefault.Name = "labelEnumIsDefault"; 110 | this.labelEnumIsDefault.Size = new System.Drawing.Size(41, 13); 111 | this.labelEnumIsDefault.TabIndex = 2; 112 | this.labelEnumIsDefault.Text = "Default"; 113 | // 114 | // EditEnumForm 115 | // 116 | this.AcceptButton = this.BtnOKButton; 117 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 118 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 119 | this.CancelButton = this.BtnCancelButton; 120 | this.ClientSize = new System.Drawing.Size(334, 90); 121 | this.Controls.Add(this.EnumIsDefaultCheckBox); 122 | this.Controls.Add(this.EnumIdTextBox); 123 | this.Controls.Add(this.EnumNameTextBox); 124 | this.Controls.Add(this.labelEnumIsDefault); 125 | this.Controls.Add(this.labelEnumName); 126 | this.Controls.Add(this.labelEnumId); 127 | this.Controls.Add(this.BtnOKButton); 128 | this.Controls.Add(this.BtnCancelButton); 129 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; 130 | this.MaximizeBox = false; 131 | this.MinimizeBox = false; 132 | this.Name = "EditEnumForm"; 133 | this.ShowIcon = false; 134 | this.ShowInTaskbar = false; 135 | this.Text = "EditEnumForm"; 136 | this.ResumeLayout(false); 137 | this.PerformLayout(); 138 | 139 | } 140 | 141 | #endregion 142 | 143 | private System.Windows.Forms.Button BtnOKButton; 144 | private System.Windows.Forms.Button BtnCancelButton; 145 | private System.Windows.Forms.Label labelEnumId; 146 | private System.Windows.Forms.TextBox EnumNameTextBox; 147 | private System.Windows.Forms.MaskedTextBox EnumIdTextBox; 148 | private System.Windows.Forms.Label labelEnumName; 149 | private System.Windows.Forms.CheckBox EnumIsDefaultCheckBox; 150 | private System.Windows.Forms.Label labelEnumIsDefault; 151 | } 152 | } -------------------------------------------------------------------------------- /Redmine.Client/EditEnumForm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Drawing; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Windows.Forms; 9 | using Redmine.Net.Api.Types; 10 | using Redmine.Client.Languages; 11 | 12 | namespace Redmine.Client 13 | { 14 | public partial class EditEnumForm : Form 15 | { 16 | public enum eFormType 17 | { 18 | New, 19 | Edit, 20 | }; 21 | public Enumerations.EnumerationItem enumValue; 22 | private eFormType type; 23 | private string enumName; // the name of the enumeration set. 24 | 25 | public EditEnumForm(string enumName, eFormType type, Enumerations.EnumerationItem enumValue) 26 | { 27 | InitializeComponent(); 28 | this.type = type; 29 | this.enumName = enumName; 30 | this.enumValue = enumValue; 31 | 32 | if (this.type == eFormType.Edit) 33 | { 34 | EnumIdTextBox.Text = enumValue.Id.ToString(); 35 | EnumNameTextBox.Text = enumValue.Name; 36 | EnumIsDefaultCheckBox.Checked = enumValue.IsDefault; 37 | } 38 | LoadLanguage(); 39 | } 40 | 41 | private void LoadLanguage() 42 | { 43 | LangTools.UpdateControlsForLanguage(this.Controls); 44 | if (type == eFormType.New) 45 | this.Text = String.Format(Lang.DlgEditEnumFormTitle_New, enumName); 46 | else 47 | this.Text = String.Format(Lang.DlgEditEnumFormTitle_Edit, enumValue.Name, enumName); 48 | } 49 | 50 | private void BtnOKButton_Click(object sender, EventArgs e) 51 | { 52 | if (String.IsNullOrEmpty(EnumIdTextBox.Text)) 53 | { 54 | MessageBox.Show(String.Format(Lang.Error_EnumFieldIsMandatory, labelEnumId.Text), Lang.Error, MessageBoxButtons.OK, MessageBoxIcon.Exclamation); 55 | return; 56 | } 57 | if (String.IsNullOrEmpty(EnumNameTextBox.Text)) 58 | { 59 | MessageBox.Show(String.Format(Lang.Error_EnumFieldIsMandatory, labelEnumName.Text), Lang.Error, MessageBoxButtons.OK, MessageBoxIcon.Exclamation); 60 | return; 61 | } 62 | enumValue.Id = Convert.ToInt32(EnumIdTextBox.Text); 63 | enumValue.Name = EnumNameTextBox.Text; 64 | enumValue.IsDefault = EnumIsDefaultCheckBox.Checked; 65 | this.DialogResult = DialogResult.OK; 66 | this.Close(); 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /Redmine.Client/EditEnumForm.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /Redmine.Client/EditEnumListForm.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace Redmine.Client 2 | { 3 | partial class EditEnumListForm 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.EnumerationListView = new System.Windows.Forms.ListView(); 32 | this.BtnAddButton = new System.Windows.Forms.Button(); 33 | this.BtnSaveButton = new System.Windows.Forms.Button(); 34 | this.BtnCancelButton = new System.Windows.Forms.Button(); 35 | this.BtnModifyButton = new System.Windows.Forms.Button(); 36 | this.BtnDeleteButton = new System.Windows.Forms.Button(); 37 | this.SuspendLayout(); 38 | // 39 | // EnumerationListView 40 | // 41 | this.EnumerationListView.FullRowSelect = true; 42 | this.EnumerationListView.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.Nonclickable; 43 | this.EnumerationListView.HideSelection = false; 44 | this.EnumerationListView.Location = new System.Drawing.Point(12, 12); 45 | this.EnumerationListView.MultiSelect = false; 46 | this.EnumerationListView.Name = "EnumerationListView"; 47 | this.EnumerationListView.Size = new System.Drawing.Size(296, 84); 48 | this.EnumerationListView.TabIndex = 0; 49 | this.EnumerationListView.UseCompatibleStateImageBehavior = false; 50 | this.EnumerationListView.View = System.Windows.Forms.View.Details; 51 | this.EnumerationListView.VirtualMode = true; 52 | // 53 | // BtnAddButton 54 | // 55 | this.BtnAddButton.Location = new System.Drawing.Point(314, 12); 56 | this.BtnAddButton.Name = "BtnAddButton"; 57 | this.BtnAddButton.Size = new System.Drawing.Size(68, 24); 58 | this.BtnAddButton.TabIndex = 1; 59 | this.BtnAddButton.Text = "Add"; 60 | this.BtnAddButton.UseVisualStyleBackColor = true; 61 | this.BtnAddButton.Click += new System.EventHandler(this.BtnAddButton_Click); 62 | // 63 | // BtnSaveButton 64 | // 65 | this.BtnSaveButton.Location = new System.Drawing.Point(242, 101); 66 | this.BtnSaveButton.Margin = new System.Windows.Forms.Padding(2); 67 | this.BtnSaveButton.Name = "BtnSaveButton"; 68 | this.BtnSaveButton.Size = new System.Drawing.Size(68, 24); 69 | this.BtnSaveButton.TabIndex = 4; 70 | this.BtnSaveButton.Text = "Save"; 71 | this.BtnSaveButton.UseVisualStyleBackColor = true; 72 | this.BtnSaveButton.Click += new System.EventHandler(this.BtnSaveButton_Click); 73 | // 74 | // BtnCancelButton 75 | // 76 | this.BtnCancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel; 77 | this.BtnCancelButton.Location = new System.Drawing.Point(314, 101); 78 | this.BtnCancelButton.Margin = new System.Windows.Forms.Padding(2); 79 | this.BtnCancelButton.Name = "BtnCancelButton"; 80 | this.BtnCancelButton.Size = new System.Drawing.Size(68, 24); 81 | this.BtnCancelButton.TabIndex = 5; 82 | this.BtnCancelButton.Text = "Cancel"; 83 | this.BtnCancelButton.UseVisualStyleBackColor = true; 84 | // 85 | // BtnModifyButton 86 | // 87 | this.BtnModifyButton.Location = new System.Drawing.Point(314, 42); 88 | this.BtnModifyButton.Name = "BtnModifyButton"; 89 | this.BtnModifyButton.Size = new System.Drawing.Size(68, 24); 90 | this.BtnModifyButton.TabIndex = 2; 91 | this.BtnModifyButton.Text = "Modify"; 92 | this.BtnModifyButton.UseVisualStyleBackColor = true; 93 | this.BtnModifyButton.Click += new System.EventHandler(this.BtnModifyButton_Click); 94 | // 95 | // BtnDeleteButton 96 | // 97 | this.BtnDeleteButton.Location = new System.Drawing.Point(314, 72); 98 | this.BtnDeleteButton.Name = "BtnDeleteButton"; 99 | this.BtnDeleteButton.Size = new System.Drawing.Size(68, 24); 100 | this.BtnDeleteButton.TabIndex = 3; 101 | this.BtnDeleteButton.Text = "Delete"; 102 | this.BtnDeleteButton.UseVisualStyleBackColor = true; 103 | this.BtnDeleteButton.Click += new System.EventHandler(this.BtnDeleteButton_Click); 104 | // 105 | // EditEnumListForm 106 | // 107 | this.AcceptButton = this.BtnSaveButton; 108 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 109 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 110 | this.CancelButton = this.BtnCancelButton; 111 | this.ClientSize = new System.Drawing.Size(393, 136); 112 | this.Controls.Add(this.BtnSaveButton); 113 | this.Controls.Add(this.BtnCancelButton); 114 | this.Controls.Add(this.BtnDeleteButton); 115 | this.Controls.Add(this.BtnModifyButton); 116 | this.Controls.Add(this.BtnAddButton); 117 | this.Controls.Add(this.EnumerationListView); 118 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; 119 | this.MaximizeBox = false; 120 | this.MinimizeBox = false; 121 | this.Name = "EditEnumListForm"; 122 | this.ShowIcon = false; 123 | this.ShowInTaskbar = false; 124 | this.Text = "Edit Enumerations"; 125 | this.ResumeLayout(false); 126 | 127 | } 128 | 129 | #endregion 130 | 131 | private System.Windows.Forms.ListView EnumerationListView; 132 | private System.Windows.Forms.Button BtnAddButton; 133 | private System.Windows.Forms.Button BtnSaveButton; 134 | private System.Windows.Forms.Button BtnCancelButton; 135 | private System.Windows.Forms.Button BtnModifyButton; 136 | private System.Windows.Forms.Button BtnDeleteButton; 137 | } 138 | } -------------------------------------------------------------------------------- /Redmine.Client/EditEnumListForm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Drawing; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Windows.Forms; 9 | using Redmine.Net.Api.Types; 10 | using Redmine.Client.Languages; 11 | 12 | namespace Redmine.Client 13 | { 14 | public partial class EditEnumListForm : Form 15 | { 16 | 17 | public List enumeration { get; private set; } 18 | private string enumName; 19 | 20 | public EditEnumListForm(List enumeration, string enumName) 21 | { 22 | InitializeComponent(); 23 | this.enumName = enumName; 24 | this.enumeration = enumeration; 25 | 26 | EnumerationListView.Columns.Add("ColumnId", Lang.labelEnumId, 25); 27 | EnumerationListView.Columns.Add("ColumnName", Lang.labelEnumName, 150); 28 | EnumerationListView.Columns.Add("ColumnIsDefault", Lang.labelEnumIsDefault, 150); 29 | EnumerationListView.RetrieveVirtualItem += new RetrieveVirtualItemEventHandler(EnumerationListView_RetrieveVirtualItem); 30 | EnumerationListView.SelectedIndexChanged += new EventHandler(EnumerationListView_SelectedIndexChanged); 31 | EnumerationListView.MouseDoubleClick += new MouseEventHandler(EnumerationListView_MouseDoubleClick); 32 | EnumerationListView.VirtualListSize = enumeration.Count; 33 | 34 | LoadLanguage(); 35 | } 36 | 37 | private void LoadLanguage() 38 | { 39 | LangTools.UpdateControlsForLanguage(this.Controls); 40 | this.Text = String.Format(Lang.DlgEditEnumListFormTitle, enumName); 41 | } 42 | 43 | void EnumerationListView_MouseDoubleClick(object sender, MouseEventArgs e) 44 | { 45 | BtnModifyButton_Click(null, null); 46 | } 47 | 48 | void EnumerationListView_SelectedIndexChanged(object sender, EventArgs e) 49 | { 50 | BtnDeleteButton.Enabled = EnumerationListView.SelectedIndices.Count != 0; 51 | BtnModifyButton.Enabled = EnumerationListView.SelectedIndices.Count != 0; 52 | } 53 | 54 | public void EnumerationListView_RetrieveVirtualItem(object Sender, RetrieveVirtualItemEventArgs e) 55 | { 56 | if (e.ItemIndex < 0 || e.ItemIndex >= enumeration.Count) 57 | return; 58 | Enumerations.EnumerationItem item = enumeration[e.ItemIndex]; 59 | e.Item = new ListViewItem(); 60 | e.Item.Text = item.Id.ToString(); 61 | e.Item.SubItems.Add(item.Name); 62 | e.Item.SubItems.Add(item.IsDefault.ToString()); 63 | } 64 | 65 | private void BtnAddButton_Click(object sender, EventArgs e) 66 | { 67 | EditEnumForm dlg = new EditEnumForm(enumName, EditEnumForm.eFormType.New, new Enumerations.EnumerationItem { Id = 0, Name = "", IsDefault = false }); 68 | do 69 | { 70 | DialogResult result = dlg.ShowDialog(this); 71 | if (result != DialogResult.OK) 72 | return; 73 | if (IsUnique(dlg.enumValue)) 74 | { 75 | AddItem(dlg.enumValue); 76 | return; 77 | } 78 | if (MessageBox.Show(Lang.Error_EnumMustBeUnique, Lang.Error, MessageBoxButtons.OKCancel, MessageBoxIcon.Exclamation) != DialogResult.OK) 79 | return; 80 | } 81 | while (true); 82 | } 83 | 84 | private void AddItem(Enumerations.EnumerationItem item) 85 | { 86 | enumeration.Add(item); 87 | EnumerationListView.VirtualListSize = enumeration.Count; 88 | } 89 | 90 | private void DeleteItem(Enumerations.EnumerationItem item) 91 | { 92 | enumeration.Remove(item); 93 | EnumerationListView.VirtualListSize = enumeration.Count; 94 | } 95 | 96 | private bool IsUnique(Enumerations.EnumerationItem item) 97 | { 98 | return IsUnique(item, null); 99 | } 100 | 101 | private bool IsUnique(Enumerations.EnumerationItem item, Enumerations.EnumerationItem itemOri) 102 | { 103 | foreach (Enumerations.EnumerationItem real in enumeration) 104 | { 105 | if (itemOri != null) 106 | if (itemOri == real) 107 | continue; 108 | if (real.Id == item.Id || 109 | String.Compare(item.Name, item.Name, true) == 0 || 110 | real.IsDefault == item.IsDefault) 111 | return false; 112 | } 113 | return true; 114 | } 115 | 116 | private Enumerations.EnumerationItem GetCurrentSelectedItem() 117 | { 118 | if (EnumerationListView.SelectedIndices.Count != 1) 119 | return null; 120 | return enumeration[EnumerationListView.SelectedIndices[0]]; 121 | } 122 | 123 | private void BtnDeleteButton_Click(object sender, EventArgs e) 124 | { 125 | Enumerations.EnumerationItem item = GetCurrentSelectedItem(); 126 | if (item == null) 127 | return; 128 | DeleteItem(item); 129 | } 130 | 131 | private void BtnModifyButton_Click(object sender, EventArgs e) 132 | { 133 | Enumerations.EnumerationItem item = GetCurrentSelectedItem(); 134 | if (item == null) 135 | return; 136 | EditEnumForm dlg = new EditEnumForm(enumName, EditEnumForm.eFormType.Edit, item); 137 | do 138 | { 139 | DialogResult result = dlg.ShowDialog(this); 140 | if (result != DialogResult.OK) 141 | return; 142 | if (IsUnique(dlg.enumValue, item)) 143 | { 144 | UpdateItem(dlg.enumValue, item); 145 | return; 146 | } 147 | if (MessageBox.Show(Lang.Error_EnumMustBeUnique, Lang.Error, MessageBoxButtons.OKCancel, MessageBoxIcon.Exclamation) != DialogResult.OK) 148 | return; 149 | } 150 | while (true); 151 | } 152 | 153 | private void UpdateItem(Enumerations.EnumerationItem newItem, Enumerations.EnumerationItem original) 154 | { 155 | foreach (Enumerations.EnumerationItem item in enumeration) 156 | { 157 | if (original == item) 158 | { 159 | item.Id = newItem.Id; 160 | item.Name = newItem.Name; 161 | item.IsDefault = newItem.IsDefault; 162 | EnumerationListView.Invalidate(); 163 | return; 164 | } 165 | } 166 | } 167 | 168 | private void BtnSaveButton_Click(object sender, EventArgs e) 169 | { 170 | this.DialogResult = DialogResult.OK; 171 | this.Close(); 172 | } 173 | } 174 | } 175 | -------------------------------------------------------------------------------- /Redmine.Client/EditEnumListForm.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /Redmine.Client/Enumerations.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.Globalization; 5 | using Redmine.Net.Api; 6 | using Redmine.Net.Api.Types; 7 | using System.IO; 8 | using System.Xml; 9 | using System.Xml.Schema; 10 | using System.Xml.Serialization; 11 | using System.Windows.Forms; 12 | using Redmine.Net.Api.Extensions; 13 | 14 | namespace Redmine.Client 15 | { 16 | /// 17 | /// The enumerations we need that are not available through the Redmine API 18 | /// 19 | public static class Enumerations 20 | { 21 | [XmlRoot("enumeration_item")] 22 | public class EnumerationItem : IXmlSerializable, IEquatable 23 | { 24 | [XmlElement("id")] 25 | public int Id { get; set; } 26 | 27 | [XmlElement("name")] 28 | public string Name { get; set; } 29 | 30 | [XmlElement("is_default")] 31 | public bool IsDefault { get; set; } 32 | 33 | public IdentifiableName ToIdentifiableName() 34 | { 35 | return new IdentifiableName() { Id = this.Id, Name = this.Name }; 36 | } 37 | 38 | #region Implementation of IXmlSerializable 39 | 40 | public XmlSchema GetSchema() 41 | { 42 | return null; 43 | } 44 | 45 | /// 46 | /// Generates an object from its XML representation. 47 | /// 48 | /// The stream from which the object is deserialized. 49 | public void ReadXml(XmlReader reader) 50 | { 51 | reader.Read(); 52 | while (!reader.EOF) 53 | { 54 | if (reader.IsEmptyElement && !reader.HasAttributes) 55 | { 56 | reader.Read(); 57 | continue; 58 | } 59 | 60 | switch (reader.Name) 61 | { 62 | case "id": Id = reader.ReadElementContentAsInt(); break; 63 | 64 | case "name": Name = reader.ReadElementContentAsString(); break; 65 | 66 | case "is_default": IsDefault = reader.ReadElementContentAsBoolean(); break; 67 | 68 | default: reader.Read(); break; 69 | } 70 | } 71 | } 72 | 73 | public void WriteXml(XmlWriter writer) 74 | { 75 | writer.WriteAttributeString("id", Id.ToString(CultureInfo.InvariantCulture)); 76 | writer.WriteAttributeString("name", Name); 77 | writer.WriteAttributeString("is_default", IsDefault.ToString(CultureInfo.InvariantCulture)); 78 | } 79 | 80 | #endregion Implementation of IXmlSerializable 81 | 82 | #region Implementation of IEquatable 83 | 84 | public bool Equals(EnumerationItem other) 85 | { 86 | if (other == null) return false; 87 | 88 | return Id == other.Id && Name == other.Name && IsDefault == other.IsDefault; 89 | } 90 | 91 | #endregion Implementation of IEquatable 92 | }; 93 | 94 | /// 95 | /// Priorities that can be used in issues 96 | /// 97 | public static List IssuePriorities { get; set; } 98 | 99 | /// 100 | /// Activities that can be used to commit time 101 | /// 102 | public static List Activities { get; set; } 103 | 104 | /// 105 | /// Load all enumerations from file 106 | /// 107 | public static void LoadAll() 108 | { 109 | LoadIssuePriorities(); 110 | LoadActivities(); 111 | } 112 | 113 | public static void LoadIssuePriorities() 114 | { 115 | bool loadDefault = false; 116 | try 117 | { 118 | IssuePriorities = Load("IssuePriorities"); 119 | } 120 | catch (Exception) { loadDefault = true; } 121 | if (loadDefault) 122 | { 123 | IssuePriorities = new List { 124 | new EnumerationItem { Id = 3, Name = "Low", IsDefault = false }, 125 | new EnumerationItem { Id = 4, Name = "Normal", IsDefault = true }, 126 | new EnumerationItem { Id = 5, Name = "High", IsDefault = false }, 127 | new EnumerationItem { Id = 6, Name = "Urgent", IsDefault = false }, 128 | new EnumerationItem { Id = 7, Name = "Immediate", IsDefault = false } 129 | }; 130 | } 131 | } 132 | 133 | public static void LoadActivities() 134 | { 135 | bool loadDefault = false; 136 | try 137 | { 138 | Activities = Load("Activities"); 139 | } 140 | catch (Exception) { loadDefault = true; } 141 | if (loadDefault) 142 | { 143 | Activities = new List { 144 | new EnumerationItem { Id = 8, Name = "Design", IsDefault = true }, 145 | new EnumerationItem { Id = 9, Name = "Development", IsDefault = false } 146 | }; 147 | } 148 | } 149 | 150 | public static List Load(string listName) 151 | { 152 | string fileName = Application.CommonAppDataPath + "\\" + listName + ".xml"; 153 | FileStream f = File.OpenRead(fileName); 154 | List list = new List(); 155 | using (var xmlReader = new XmlTextReader(f)) 156 | { 157 | xmlReader.WhitespaceHandling = WhitespaceHandling.None; 158 | xmlReader.Read(); 159 | list = xmlReader.ReadElementContentAsCollection(); 160 | } 161 | return list; 162 | } 163 | 164 | public static void SaveAll() 165 | { 166 | SaveIssuePriorities(); 167 | SaveActivities(); 168 | } 169 | 170 | public static void SaveIssuePriorities() 171 | { 172 | Save(IssuePriorities, "IssuePriorities"); 173 | } 174 | 175 | public static void SaveActivities() 176 | { 177 | Save(Activities, "Activities"); 178 | } 179 | 180 | public static void Save(IList list, string listName) 181 | { 182 | var xws = new XmlWriterSettings { OmitXmlDeclaration = true }; 183 | string fileName = Application.CommonAppDataPath + "\\" + listName + ".xml"; 184 | 185 | File.Delete(fileName); 186 | FileStream f = File.OpenWrite(fileName); 187 | using (var xmlWriter = XmlWriter.Create(f, xws)) 188 | { 189 | xmlWriter.WriteCollectionAsElement(list, listName); 190 | } 191 | f.Close(); 192 | } 193 | 194 | public static void UpdateActivities(IList timeEntryActivities) 195 | { 196 | Activities.Clear(); 197 | foreach (TimeEntryActivity ta in timeEntryActivities) 198 | Activities.Add(new EnumerationItem { Id = ta.Id, Name = ta.Name, IsDefault = ta.IsDefault } ); 199 | } 200 | 201 | public static void UpdateIssuePriorities(IList issuePriorities) 202 | { 203 | IssuePriorities.Clear(); 204 | foreach (IssuePriority ip in issuePriorities) 205 | IssuePriorities.Add(new EnumerationItem { Id = ip.Id, Name = ip.Name, IsDefault = ip.IsDefault }); 206 | } 207 | 208 | } 209 | 210 | } 211 | -------------------------------------------------------------------------------- /Redmine.Client/IssueFormData.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using Redmine.Net.Api.Types; 5 | 6 | namespace Redmine.Client 7 | { 8 | 9 | internal class IssueFormData 10 | { 11 | public IList Trackers { get; set; } 12 | public List Categories { get; set; } 13 | public IList Statuses { get; set; } 14 | // public List Priorities { get; set; } 15 | public List Versions { get; set; } 16 | // public List Watchers { get; set; } 17 | public List ProjectMembers { get; set; } 18 | public IList IssuePriorities { get; set; } 19 | public IList TimeEntries { get; set; } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Redmine.Client/IssueGridSelectColumns.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Drawing; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Windows.Forms; 9 | using Redmine.Client.Languages; 10 | using Redmine.Client.Properties; 11 | 12 | namespace Redmine.Client 13 | { 14 | public partial class IssueGridSelectColumns : Form 15 | { 16 | public IssueGridSelectColumns() 17 | { 18 | InitializeComponent(); 19 | LangTools.UpdateControlsForLanguage(this.Controls); 20 | 21 | radioButtonHideAssignedTo.Checked = !Settings.Default.IssueGridHeader_ShowAssignedTo; 22 | radioButtonShowAssignedTo.Checked = Settings.Default.IssueGridHeader_ShowAssignedTo; 23 | radioButtonHideCategory.Checked = !Settings.Default.IssueGridHeader_ShowCategory; 24 | radioButtonShowCategory.Checked = Settings.Default.IssueGridHeader_ShowCategory; 25 | radioButtonHideParent.Checked = !Settings.Default.IssueGridHeader_ShowParentIssue; 26 | radioButtonShowParent.Checked = Settings.Default.IssueGridHeader_ShowParentIssue; 27 | radioButtonHidePriority.Checked = !Settings.Default.IssueGridHeader_ShowPriority; 28 | radioButtonShowPriority.Checked = Settings.Default.IssueGridHeader_ShowPriority; 29 | radioButtonHideProject.Checked = !Settings.Default.IssueGridHeader_ShowProject; 30 | radioButtonShowProject.Checked = Settings.Default.IssueGridHeader_ShowProject; 31 | radioButtonHideStatus.Checked = !Settings.Default.IssueGridHeader_ShowStatus; 32 | radioButtonShowStatus.Checked = Settings.Default.IssueGridHeader_ShowStatus; 33 | radioButtonHideFixedVersion.Checked = !Settings.Default.IssueGridHeader_ShowFixedVersion; 34 | radioButtonShowFixedVersion.Checked = Settings.Default.IssueGridHeader_ShowFixedVersion; 35 | } 36 | 37 | private void BtnOKButton_Click(object sender, EventArgs e) 38 | { 39 | try 40 | { 41 | Settings.Default.UpdateSetting("IssueGridHeader_ShowAssignedTo", radioButtonShowAssignedTo.Checked); 42 | Settings.Default.UpdateSetting("IssueGridHeader_ShowCategory", radioButtonShowCategory.Checked); 43 | Settings.Default.UpdateSetting("IssueGridHeader_ShowParentIssue", radioButtonShowParent.Checked); 44 | Settings.Default.UpdateSetting("IssueGridHeader_ShowPriority", radioButtonShowPriority.Checked); 45 | Settings.Default.UpdateSetting("IssueGridHeader_ShowProject", radioButtonShowProject.Checked); 46 | Settings.Default.UpdateSetting("IssueGridHeader_ShowStatus", radioButtonShowStatus.Checked); 47 | Settings.Default.UpdateSetting("IssueGridHeader_ShowFixedVersion", radioButtonShowFixedVersion.Checked); 48 | Settings.Default.Save(); 49 | 50 | this.DialogResult = DialogResult.OK; 51 | this.Close(); 52 | } 53 | catch (Exception ex) 54 | { 55 | MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Stop); 56 | } 57 | } 58 | 59 | private void BtnCancelButton_Click(object sender, EventArgs e) 60 | { 61 | this.DialogResult = DialogResult.Cancel; 62 | this.Close(); 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /Redmine.Client/IssueGridSelectColumns.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /Redmine.Client/Languages/LangTools.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Globalization; 6 | using System.Windows.Forms; 7 | using Redmine.Net.Api.Types; 8 | 9 | namespace Redmine.Client.Languages 10 | { 11 | internal static class LangTools 12 | { 13 | // public static CultureInfo language = System.Globalization.CultureInfo.CurrentUICulture; 14 | 15 | public static void UpdateControlsForLanguage(Control.ControlCollection formControls) 16 | { 17 | foreach (Control c in formControls) 18 | { 19 | if (!String.IsNullOrEmpty(Lang.ResourceManager.GetString(c.Name, Lang.Culture))) 20 | c.Text = Lang.ResourceManager.GetString(c.Name, Lang.Culture); 21 | if (c.Controls.Count != 0) 22 | UpdateControlsForLanguage(c.Controls); 23 | } 24 | } 25 | 26 | internal static void UpdateControlsForLanguage(ToolStripItemCollection toolStripItems) 27 | { 28 | foreach (ToolStripItem i in toolStripItems) 29 | { 30 | if (!String.IsNullOrEmpty(Lang.ResourceManager.GetString(i.Name, Lang.Culture))) 31 | i.Text = Lang.ResourceManager.GetString(i.Name, Lang.Culture); 32 | } 33 | } 34 | public static string GetTextForApiVersion(ApiVersion apiVersion) 35 | { 36 | return Lang.ResourceManager.GetString("ApiVersion_" + apiVersion.ToString(), Lang.Culture); 37 | } 38 | 39 | public static string GetIssueField(string fieldName) 40 | { 41 | return Lang.ResourceManager.GetString("IssueField_" + fieldName.ToLower(Lang.Culture), Lang.Culture); 42 | } 43 | 44 | public static string CreateUpdatedText(string fieldName, string from, string to) 45 | { 46 | string basicFormatString; 47 | if (from != null && to != null && from != to) 48 | basicFormatString = Lang.UpdatedField_UpdatedTo; 49 | else if (from == null && to != null) 50 | basicFormatString = Lang.UpdatedField_SetTo; 51 | else if (from != null && to == null) 52 | basicFormatString = Lang.UpdatedField_Deleted; 53 | else 54 | return ""; // nothing changed... 55 | return String.Format(basicFormatString, GetIssueField(fieldName), from, to); 56 | } 57 | public static string CreateUpdatedText(string fieldName, IdentifiableName from, IdentifiableName to) 58 | { 59 | return CreateUpdatedText(fieldName, from != null ? from.Name : null, to != null ? to.Name : null); 60 | } 61 | public static string CreateUpdatedText(string fieldName, DateTime? from, DateTime? to, string fmt) 62 | { 63 | return CreateUpdatedText(fieldName, from.HasValue ? from.Value.ToString(fmt, Lang.Culture) : null, to.HasValue ? to.Value.ToString(fmt, Lang.Culture) : null); 64 | } 65 | public static string CreateUpdatedText(string fieldName, float? from, float? to, string fmt) 66 | { 67 | return CreateUpdatedText(fieldName, from.HasValue ? from.Value.ToString(fmt, Lang.Culture) : null, to.HasValue ? to.Value.ToString(fmt, Lang.Culture) : null); 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /Redmine.Client/OpenSpecificIssueForm.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace Redmine.Client 2 | { 3 | partial class OpenSpecificIssueForm 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.BtnOKButton = new System.Windows.Forms.Button(); 32 | this.BtnCancelButton = new System.Windows.Forms.Button(); 33 | this.labelIssueNumberToOpen = new System.Windows.Forms.Label(); 34 | this.textBoxIssueNumber = new System.Windows.Forms.TextBox(); 35 | this.SuspendLayout(); 36 | // 37 | // BtnOKButton 38 | // 39 | this.BtnOKButton.Location = new System.Drawing.Point(153, 40); 40 | this.BtnOKButton.Margin = new System.Windows.Forms.Padding(2); 41 | this.BtnOKButton.Name = "BtnOKButton"; 42 | this.BtnOKButton.Size = new System.Drawing.Size(68, 24); 43 | this.BtnOKButton.TabIndex = 2; 44 | this.BtnOKButton.Text = "OK"; 45 | this.BtnOKButton.UseVisualStyleBackColor = true; 46 | this.BtnOKButton.Click += new System.EventHandler(this.BtnOKButton_Click); 47 | // 48 | // BtnCancelButton 49 | // 50 | this.BtnCancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel; 51 | this.BtnCancelButton.Location = new System.Drawing.Point(225, 40); 52 | this.BtnCancelButton.Margin = new System.Windows.Forms.Padding(2); 53 | this.BtnCancelButton.Name = "BtnCancelButton"; 54 | this.BtnCancelButton.Size = new System.Drawing.Size(68, 24); 55 | this.BtnCancelButton.TabIndex = 3; 56 | this.BtnCancelButton.Text = "Cancel"; 57 | this.BtnCancelButton.UseVisualStyleBackColor = true; 58 | // 59 | // labelIssueNumberToOpen 60 | // 61 | this.labelIssueNumberToOpen.AutoSize = true; 62 | this.labelIssueNumberToOpen.Location = new System.Drawing.Point(12, 15); 63 | this.labelIssueNumberToOpen.Name = "labelIssueNumberToOpen"; 64 | this.labelIssueNumberToOpen.Size = new System.Drawing.Size(106, 13); 65 | this.labelIssueNumberToOpen.TabIndex = 0; 66 | this.labelIssueNumberToOpen.Text = "Issuenumber to open"; 67 | // 68 | // textBoxIssueNumber 69 | // 70 | this.textBoxIssueNumber.Location = new System.Drawing.Point(153, 12); 71 | this.textBoxIssueNumber.MaxLength = 20; 72 | this.textBoxIssueNumber.Name = "textBoxIssueNumber"; 73 | this.textBoxIssueNumber.Size = new System.Drawing.Size(95, 20); 74 | this.textBoxIssueNumber.TabIndex = 1; 75 | this.textBoxIssueNumber.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.textBoxIssueNumber_KeyPress); 76 | // 77 | // OpenSpecificIssueForm 78 | // 79 | this.AcceptButton = this.BtnOKButton; 80 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 81 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 82 | this.CancelButton = this.BtnCancelButton; 83 | this.ClientSize = new System.Drawing.Size(304, 75); 84 | this.Controls.Add(this.textBoxIssueNumber); 85 | this.Controls.Add(this.labelIssueNumberToOpen); 86 | this.Controls.Add(this.BtnOKButton); 87 | this.Controls.Add(this.BtnCancelButton); 88 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; 89 | this.MaximizeBox = false; 90 | this.MinimizeBox = false; 91 | this.Name = "OpenSpecificIssueForm"; 92 | this.ShowIcon = false; 93 | this.ShowInTaskbar = false; 94 | this.Text = "OpenSpecificIssueForm"; 95 | this.ResumeLayout(false); 96 | this.PerformLayout(); 97 | 98 | } 99 | 100 | #endregion 101 | 102 | private System.Windows.Forms.Button BtnOKButton; 103 | private System.Windows.Forms.Button BtnCancelButton; 104 | private System.Windows.Forms.Label labelIssueNumberToOpen; 105 | private System.Windows.Forms.TextBox textBoxIssueNumber; 106 | } 107 | } -------------------------------------------------------------------------------- /Redmine.Client/OpenSpecificIssueForm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Drawing; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Windows.Forms; 9 | using Redmine.Client.Languages; 10 | 11 | namespace Redmine.Client 12 | { 13 | public partial class OpenSpecificIssueForm : Form 14 | { 15 | public OpenSpecificIssueForm() 16 | { 17 | InitializeComponent(); 18 | this.Text = Lang.DlgOpenSpecificIssueTitle; 19 | LangTools.UpdateControlsForLanguage(this.Controls); 20 | if (labelIssueNumberToOpen.Size.Width > Size.Width - textBoxIssueNumber.Location.X - labelIssueNumberToOpen.Location.X - 15) 21 | { 22 | if (labelIssueNumberToOpen.Size.Width + textBoxIssueNumber.Size.Width + 15 > Size.Width - labelIssueNumberToOpen.Location.X - 15) 23 | this.Size = new Size(labelIssueNumberToOpen.Location.X + labelIssueNumberToOpen.Size.Width + textBoxIssueNumber.Size.Width + 30, this.Size.Height); 24 | textBoxIssueNumber.Location = new Point(labelIssueNumberToOpen.Location.X + labelIssueNumberToOpen.Size.Width + 10, textBoxIssueNumber.Location.Y); 25 | } 26 | } 27 | private int issueNumber = 0; 28 | public int IssueNumber { get { return issueNumber; } } 29 | 30 | private void textBoxIssueNumber_KeyPress(object sender, KeyPressEventArgs e) 31 | { 32 | if (!RedmineClientForm.CheckNumericValue(new string(e.KeyChar, 1), 0, 9) && e.KeyChar != '\b') 33 | e.Handled = true; 34 | } 35 | 36 | private void BtnOKButton_Click(object sender, EventArgs e) 37 | { 38 | bool success = Int32.TryParse(textBoxIssueNumber.Text, out issueNumber); 39 | if (!success || issueNumber == 0) 40 | { 41 | MessageBox.Show(Lang.Error_ValueOutOfRange, Lang.Error, MessageBoxButtons.OK, MessageBoxIcon.Error); 42 | return; 43 | } 44 | this.DialogResult = DialogResult.OK; 45 | this.Close(); 46 | } 47 | 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Redmine.Client/OpenSpecificIssueForm.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /Redmine.Client/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows.Forms; 3 | 4 | namespace Redmine.Client 5 | { 6 | public enum DialogType 7 | { 8 | New, 9 | Edit, 10 | }; 11 | 12 | static class Program 13 | { 14 | /// 15 | /// The main entry point for the application. 16 | /// 17 | [STAThread] 18 | static void Main() 19 | { 20 | try 21 | { 22 | AppDomain.CurrentDomain.UnhandledException += new 23 | UnhandledExceptionEventHandler(CurrentDomain_UnhandledException); 24 | Application.EnableVisualStyles(); 25 | Application.SetCompatibleTextRenderingDefault(false); 26 | } 27 | catch (Exception) 28 | { } 29 | try 30 | { 31 | Application.Run(RedmineClientForm.Instance); 32 | } 33 | catch (Exception ex) 34 | { 35 | MessageBox.Show(ex.Message, "Start Error", MessageBoxButtons.OK, MessageBoxIcon.Error); 36 | } 37 | } 38 | 39 | /// 40 | /// Handler for the weird exceptions we are not handling in our code and especially for the CLR20r3 stuff 41 | /// 42 | /// 43 | /// 44 | static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) 45 | { 46 | Exception ex = (Exception)e.ExceptionObject; 47 | Console.WriteLine("Observed unhandled exception: {0}", ex.ToString()); 48 | } 49 | 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Redmine.Client/ProjectMember.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using Redmine.Net.Api.Types; 6 | 7 | namespace Redmine.Client 8 | { 9 | /// 10 | /// Interface for showing Assignee information 11 | /// 12 | public interface IProjectMember 13 | { 14 | /// 15 | /// Gets the id. 16 | /// 17 | /// The id of the assignee. 18 | int Id { get; } 19 | 20 | /// 21 | /// Gets the name. 22 | /// 23 | /// The name of the assignee. 24 | string Name { get; } 25 | } 26 | 27 | public class ProjectMember : IProjectMember 28 | { 29 | private ProjectMembership member; 30 | 31 | public ProjectMember() 32 | { 33 | this.member = new ProjectMembership { User = new IdentifiableName { Id = 0, Name = "" } }; 34 | } 35 | public ProjectMember(User user) 36 | { 37 | this.member = new ProjectMembership { User = new IdentifiableName { Id = user.Id, Name = user.CompleteName() } }; 38 | } 39 | public ProjectMember(ProjectMembership projectMember) 40 | { 41 | this.member = projectMember; 42 | } 43 | public int Id { get { if (member.User == null) return member.Group.Id; else return member.User.Id; } } 44 | public string Name { get { if (member.User == null) return member.Group.Name; else return member.User.Name; } } 45 | /// 46 | /// Get the inner member of the projectmembership 47 | /// 48 | public ProjectMembership Member { get { return member; } } 49 | 50 | public static ProjectMember MembershipToMember(ProjectMembership projectMember) 51 | { 52 | return new ProjectMember(projectMember); 53 | } 54 | 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /Redmine.Client/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyTitle("RedmineClient")] 8 | [assembly: AssemblyDescription("Redmine desktop client tool")] 9 | [assembly: AssemblyConfiguration("")] 10 | [assembly: AssemblyCompany("")] 11 | [assembly: AssemblyProduct("RedmineClient")] 12 | [assembly: AssemblyCopyright("Copyright © Pavel Kalian 2009, Copyright © Bas van Leeuwen 2012-2013")] 13 | [assembly: AssemblyTrademark("")] 14 | [assembly: AssemblyCulture("")] 15 | 16 | // Setting ComVisible to false makes the types in this assembly not visible 17 | // to COM components. If you need to access a type in this assembly from 18 | // COM, set the ComVisible attribute to true on that type. 19 | [assembly: ComVisible(false)] 20 | 21 | // The following GUID is for the ID of the typelib if this project is exposed to COM 22 | [assembly: Guid("e2f31721-fc08-48ad-8e6d-715af20484b1")] 23 | 24 | // Version information for an assembly consists of the following four values: 25 | // 26 | // Major Version 27 | // Minor Version 28 | // Build Number 29 | // Revision 30 | // 31 | // You can specify all the values or you can default the Build and Revision Numbers 32 | // by using the '*' as shown below: 33 | // [assembly: AssemblyVersion("1.0.*")] 34 | [assembly: AssemblyVersion("2.0.8.0")] 35 | [assembly: AssemblyFileVersion("2.0.8.0")] 36 | -------------------------------------------------------------------------------- /Redmine.Client/Properties/Resources.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | 122 | ..\res\clock.ico;System.Drawing.Icon, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a 123 | 124 | 125 | ..\res\aboutclock.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a 126 | 127 | -------------------------------------------------------------------------------- /Redmine.Client/Properties/Resources1.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace Redmine.Client.Properties { 12 | using System; 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal Resources() { 33 | } 34 | 35 | /// 36 | /// Returns the cached ResourceManager instance used by this class. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Redmine.Client.Properties.Resources", typeof(Resources).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Overrides the current thread's CurrentUICulture property for all 51 | /// resource lookups using this strongly typed resource class. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | 63 | /// 64 | /// Looks up a localized resource of type System.Drawing.Bitmap. 65 | /// 66 | internal static System.Drawing.Bitmap aboutclock { 67 | get { 68 | object obj = ResourceManager.GetObject("aboutclock", resourceCulture); 69 | return ((System.Drawing.Bitmap)(obj)); 70 | } 71 | } 72 | 73 | /// 74 | /// Looks up a localized resource of type System.Drawing.Icon similar to (Icon). 75 | /// 76 | internal static System.Drawing.Icon clock { 77 | get { 78 | object obj = ResourceManager.GetObject("clock", resourceCulture); 79 | return ((System.Drawing.Icon)(obj)); 80 | } 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /Redmine.Client/Properties/Settings.cs: -------------------------------------------------------------------------------- 1 | namespace Redmine.Client.Properties { 2 | 3 | 4 | // This class allows you to handle specific events on the settings class: 5 | // The SettingChanging event is raised before a setting's value is changed. 6 | // The PropertyChanged event is raised after a setting's value is changed. 7 | // The SettingsLoaded event is raised after the setting values are loaded. 8 | // The SettingsSaving event is raised before the setting values are saved. 9 | internal sealed partial class Settings { 10 | 11 | public Settings() { 12 | // // To add event handlers for saving and changing settings, uncomment the lines below: 13 | // 14 | // this.SettingChanging += this.SettingChangingEventHandler; 15 | // 16 | // this.SettingsSaving += this.SettingsSavingEventHandler; 17 | // 18 | } 19 | 20 | private void SettingChangingEventHandler(object sender, System.Configuration.SettingChangingEventArgs e) { 21 | // Add code to handle the SettingChangingEvent event here. 22 | } 23 | 24 | private void SettingsSavingEventHandler(object sender, System.ComponentModel.CancelEventArgs e) { 25 | // Add code to handle the SettingsSaving event here. 26 | } 27 | 28 | public void SetTickingTick(bool ticking, int ticks) 29 | { 30 | Settings.Default.PropertyValues["IsTicking"].PropertyValue = ticking; 31 | Settings.Default.PropertyValues["TickingTicks"].PropertyValue = ticks; 32 | Settings.Default.Save(); 33 | } 34 | 35 | public void SetIssueGridSort(string columnName, System.Windows.Forms.SortOrder order) 36 | { 37 | Settings.Default.PropertyValues["IssueGridSortColumn"].PropertyValue = columnName; 38 | Settings.Default.PropertyValues["IssueGridSortOrder"].PropertyValue = order; 39 | Settings.Default.Save(); 40 | } 41 | public bool ShowIssueGridColumn(string columnName) 42 | { 43 | if (Settings.Default.PropertyValues["IssueGridHeader_Show" + columnName] != null) 44 | return (bool)Settings.Default.PropertyValues["IssueGridHeader_Show" + columnName].PropertyValue; 45 | return false; 46 | } 47 | 48 | public void UpdateSetting(string settingName, T setting) 49 | { 50 | Settings.Default.PropertyValues[settingName].PropertyValue = setting; 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Redmine.Client/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | my username 7 | 8 | 9 | http://redmine.example.org 10 | 11 | 12 | my password 13 | 14 | 15 | True 16 | 17 | 18 | True 19 | 20 | 21 | True 22 | 23 | 24 | True 25 | 26 | 27 | 0 28 | 29 | 30 | 0 31 | 32 | 33 | 540 34 | 35 | 36 | 460 37 | 38 | 39 | 0 40 | 41 | 42 | 0 43 | 44 | 45 | 0 46 | 47 | 48 | en 49 | 50 | 51 | 3 52 | 53 | 54 | 0 55 | 56 | 57 | False 58 | 59 | 60 | False 61 | 62 | 63 | 0 64 | 65 | 66 | False 67 | 68 | 69 | False 70 | 71 | 72 | 0 73 | 74 | 75 | 0 76 | 77 | 78 | 492 79 | 80 | 81 | 374 82 | 83 | 84 | True 85 | 86 | 87 | None 88 | 89 | 90 | Id 91 | 92 | 93 | False 94 | 95 | 96 | False 97 | 98 | 99 | False 100 | 101 | 102 | False 103 | 104 | 105 | False 106 | 107 | 108 | False 109 | 110 | 111 | False 112 | 113 | 114 | xml 115 | 116 | 117 | True 118 | 119 | 120 | True 121 | 122 | 123 | -------------------------------------------------------------------------------- /Redmine.Client/Properties/app.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | my username 12 | 13 | 14 | http://redmine.example.org 15 | 16 | 17 | my password 18 | 19 | 20 | True 21 | 22 | 23 | True 24 | 25 | 26 | True 27 | 28 | 29 | True 30 | 31 | 32 | 0 33 | 34 | 35 | 0 36 | 37 | 38 | 0 39 | 40 | 41 | 0 42 | 43 | 44 | 0 45 | 46 | 47 | 0 48 | 49 | 50 | 0 51 | 52 | 53 | en-US 54 | 55 | 56 | 3 57 | 58 | 59 | 0 60 | 61 | 62 | False 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /Redmine.Client/SettingsForm.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /Redmine.Client/TimeEntriesForm.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace Redmine.Client 2 | { 3 | partial class TimeEntriesForm 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.BtnOKButton = new System.Windows.Forms.Button(); 32 | this.DataGridViewTimeEntries = new System.Windows.Forms.DataGridView(); 33 | this.BtnDeleteButton = new System.Windows.Forms.Button(); 34 | this.BtnModifyButton = new System.Windows.Forms.Button(); 35 | this.BtnAddButton = new System.Windows.Forms.Button(); 36 | ((System.ComponentModel.ISupportInitialize)(this.DataGridViewTimeEntries)).BeginInit(); 37 | this.SuspendLayout(); 38 | // 39 | // BtnOKButton 40 | // 41 | this.BtnOKButton.Anchor = System.Windows.Forms.AnchorStyles.Bottom; 42 | this.BtnOKButton.Location = new System.Drawing.Point(192, 235); 43 | this.BtnOKButton.Margin = new System.Windows.Forms.Padding(2); 44 | this.BtnOKButton.Name = "BtnOKButton"; 45 | this.BtnOKButton.Size = new System.Drawing.Size(68, 24); 46 | this.BtnOKButton.TabIndex = 26; 47 | this.BtnOKButton.Text = "OK"; 48 | this.BtnOKButton.UseVisualStyleBackColor = true; 49 | this.BtnOKButton.Click += new System.EventHandler(this.BtnOKButton_Click); 50 | // 51 | // DataGridViewTimeEntries 52 | // 53 | this.DataGridViewTimeEntries.AllowUserToAddRows = false; 54 | this.DataGridViewTimeEntries.AllowUserToDeleteRows = false; 55 | this.DataGridViewTimeEntries.AllowUserToResizeRows = false; 56 | this.DataGridViewTimeEntries.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 57 | | System.Windows.Forms.AnchorStyles.Left) 58 | | System.Windows.Forms.AnchorStyles.Right))); 59 | this.DataGridViewTimeEntries.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize; 60 | this.DataGridViewTimeEntries.Location = new System.Drawing.Point(12, 12); 61 | this.DataGridViewTimeEntries.MultiSelect = false; 62 | this.DataGridViewTimeEntries.Name = "DataGridViewTimeEntries"; 63 | this.DataGridViewTimeEntries.ReadOnly = true; 64 | this.DataGridViewTimeEntries.SelectionMode = System.Windows.Forms.DataGridViewSelectionMode.FullRowSelect; 65 | this.DataGridViewTimeEntries.Size = new System.Drawing.Size(354, 218); 66 | this.DataGridViewTimeEntries.TabIndex = 28; 67 | this.DataGridViewTimeEntries.CellFormatting += new System.Windows.Forms.DataGridViewCellFormattingEventHandler(this.DataGridViewTimeEntries_CellFormatting); 68 | this.DataGridViewTimeEntries.CellMouseDoubleClick += new System.Windows.Forms.DataGridViewCellMouseEventHandler(this.DataGridViewTimeEntries_CellMouseDoubleClick); 69 | // 70 | // BtnDeleteButton 71 | // 72 | this.BtnDeleteButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); 73 | this.BtnDeleteButton.Location = new System.Drawing.Point(372, 72); 74 | this.BtnDeleteButton.Name = "BtnDeleteButton"; 75 | this.BtnDeleteButton.Size = new System.Drawing.Size(68, 24); 76 | this.BtnDeleteButton.TabIndex = 31; 77 | this.BtnDeleteButton.Text = "Delete"; 78 | this.BtnDeleteButton.UseVisualStyleBackColor = true; 79 | this.BtnDeleteButton.Click += new System.EventHandler(this.BtnDeleteButton_Click); 80 | // 81 | // BtnModifyButton 82 | // 83 | this.BtnModifyButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); 84 | this.BtnModifyButton.Location = new System.Drawing.Point(372, 42); 85 | this.BtnModifyButton.Name = "BtnModifyButton"; 86 | this.BtnModifyButton.Size = new System.Drawing.Size(68, 24); 87 | this.BtnModifyButton.TabIndex = 30; 88 | this.BtnModifyButton.Text = "Modify"; 89 | this.BtnModifyButton.UseVisualStyleBackColor = true; 90 | this.BtnModifyButton.Click += new System.EventHandler(this.BtnModifyButton_Click); 91 | // 92 | // BtnAddButton 93 | // 94 | this.BtnAddButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); 95 | this.BtnAddButton.Location = new System.Drawing.Point(372, 12); 96 | this.BtnAddButton.Name = "BtnAddButton"; 97 | this.BtnAddButton.Size = new System.Drawing.Size(68, 24); 98 | this.BtnAddButton.TabIndex = 29; 99 | this.BtnAddButton.Text = "Add"; 100 | this.BtnAddButton.UseVisualStyleBackColor = true; 101 | this.BtnAddButton.Click += new System.EventHandler(this.BtnAddButton_Click); 102 | // 103 | // TimeEntriesForm 104 | // 105 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 106 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 107 | this.ClientSize = new System.Drawing.Size(452, 270); 108 | this.Controls.Add(this.BtnDeleteButton); 109 | this.Controls.Add(this.BtnModifyButton); 110 | this.Controls.Add(this.BtnAddButton); 111 | this.Controls.Add(this.DataGridViewTimeEntries); 112 | this.Controls.Add(this.BtnOKButton); 113 | this.Name = "TimeEntriesForm"; 114 | this.ShowIcon = false; 115 | this.ShowInTaskbar = false; 116 | this.Text = "TimeEntriesForm"; 117 | this.Load += new System.EventHandler(this.TimeEntriesForm_Load); 118 | ((System.ComponentModel.ISupportInitialize)(this.DataGridViewTimeEntries)).EndInit(); 119 | this.ResumeLayout(false); 120 | 121 | } 122 | 123 | #endregion 124 | 125 | private System.Windows.Forms.Button BtnOKButton; 126 | private System.Windows.Forms.DataGridView DataGridViewTimeEntries; 127 | private System.Windows.Forms.Button BtnDeleteButton; 128 | private System.Windows.Forms.Button BtnModifyButton; 129 | private System.Windows.Forms.Button BtnAddButton; 130 | } 131 | } -------------------------------------------------------------------------------- /Redmine.Client/TimeEntriesForm.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /Redmine.Client/TimeEntryForm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Drawing; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Windows.Forms; 9 | using Redmine.Net.Api.Types; 10 | using Redmine.Client.Languages; 11 | 12 | namespace Redmine.Client 13 | { 14 | public partial class TimeEntryForm : BgWorker 15 | { 16 | public enum eFormType 17 | { 18 | New, 19 | Edit, 20 | }; 21 | public TimeEntry CurTimeEntry { get; set; } 22 | private Issue issue; 23 | private IList projectMembers; 24 | private eFormType type; 25 | 26 | public TimeEntryForm(Issue issue, IList projectMembers) 27 | { 28 | InitializeComponent(); 29 | this.issue = issue; 30 | this.projectMembers = projectMembers; 31 | type = eFormType.New; 32 | CurTimeEntry = new TimeEntry(); 33 | LoadLanguage(); 34 | LoadCombos(); 35 | comboBoxByUser.SelectedValue = RedmineClientForm.Instance.CurrentUser.Id; 36 | } 37 | public TimeEntryForm(Issue issue, IList projectMembers, TimeEntry timeEntry) 38 | { 39 | InitializeComponent(); 40 | this.issue = issue; 41 | this.projectMembers = projectMembers; 42 | type = eFormType.Edit; 43 | CurTimeEntry = timeEntry; 44 | LoadLanguage(); 45 | LoadCombos(); 46 | 47 | if (CurTimeEntry.SpentOn.HasValue) 48 | datePickerSpentOn.Value = CurTimeEntry.SpentOn.Value; 49 | 50 | comboBoxByUser.SelectedValue = CurTimeEntry.User.Id; 51 | comboBoxActivity.SelectedValue = CurTimeEntry.Activity.Id; 52 | textBoxSpentHours.Text = CurTimeEntry.Hours.ToString(Lang.Culture); 53 | textBoxComment.Text = CurTimeEntry.Comments; 54 | } 55 | 56 | private void LoadCombos() 57 | { 58 | comboBoxActivity.DataSource = Enumerations.Activities; 59 | comboBoxActivity.DisplayMember = "Name"; 60 | comboBoxActivity.ValueMember = "Id"; 61 | foreach (Enumerations.EnumerationItem i in Enumerations.Activities) 62 | { 63 | if (i.IsDefault) 64 | { 65 | comboBoxActivity.SelectedValue = i.Id; 66 | break; 67 | } 68 | } 69 | comboBoxByUser.DataSource = projectMembers; 70 | comboBoxByUser.DisplayMember = "Name"; 71 | comboBoxByUser.ValueMember = "Id"; 72 | } 73 | 74 | private void LoadLanguage() 75 | { 76 | LangTools.UpdateControlsForLanguage(this.Controls); 77 | if (type == eFormType.New) 78 | { 79 | this.Text = String.Format(Lang.DlgTimeEntryFormTitle_New, issue.Id, issue.Subject); 80 | //there is a mistake in the language-string, so we added the newline also as the third ({2}) element in the format string 81 | labelTimeEntryTitle.Text = String.Format(Lang.labelTimeEntryTitle_New, issue.Id, issue.Subject, Environment.NewLine, Environment.NewLine); 82 | } 83 | else 84 | { 85 | string fmtSpentOn = ""; 86 | if (CurTimeEntry.SpentOn.HasValue) 87 | fmtSpentOn = CurTimeEntry.SpentOn.Value.ToString("d", Lang.Culture); 88 | this.Text = String.Format(Lang.DlgTimeEntryFormTitle_Edit, fmtSpentOn, issue.Id, issue.Subject); 89 | labelTimeEntryTitle.Text = String.Format(Lang.labelTimeEntryTitle_Edit, fmtSpentOn, issue.Id, issue.Subject, Environment.NewLine); 90 | } 91 | } 92 | 93 | private void BtnOKButton_Click(object sender, EventArgs e) 94 | { 95 | CurTimeEntry.SpentOn = datePickerSpentOn.Value; 96 | CurTimeEntry.Issue = new IdentifiableName() { Id = issue.Id }; 97 | CurTimeEntry.User = new IdentifiableName() { Id = ((ProjectMember)comboBoxByUser.SelectedItem).Id }; 98 | CurTimeEntry.Activity = ((Enumerations.EnumerationItem)comboBoxActivity.SelectedItem).ToIdentifiableName(); 99 | CurTimeEntry.Hours = decimal.Parse(textBoxSpentHours.Text, Lang.Culture); 100 | CurTimeEntry.Comments = textBoxComment.Text; 101 | try 102 | { 103 | if (type == eFormType.New) 104 | RedmineClientForm.redmine.CreateObject(CurTimeEntry); 105 | else 106 | RedmineClientForm.redmine.UpdateObject(CurTimeEntry.Id.ToString(), CurTimeEntry); 107 | this.DialogResult = DialogResult.OK; 108 | this.Close(); 109 | } 110 | catch (Exception ex) 111 | { 112 | MessageBox.Show(String.Format(Lang.Error_Exception, ex.Message), Lang.Error, MessageBoxButtons.OK, MessageBoxIcon.Stop); 113 | } 114 | } 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /Redmine.Client/TimeEntryForm.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /Redmine.Client/UpdateIssueNoteForm.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace Redmine.Client 2 | { 3 | partial class UpdateIssueNoteForm 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.TextBoxDescription = new System.Windows.Forms.TextBox(); 32 | this.BtnSaveButton = new System.Windows.Forms.Button(); 33 | this.BtnCancelButton = new System.Windows.Forms.Button(); 34 | this.labelUpdateIssueNote = new System.Windows.Forms.Label(); 35 | this.SuspendLayout(); 36 | // 37 | // TextBoxDescription 38 | // 39 | this.TextBoxDescription.AcceptsReturn = true; 40 | this.TextBoxDescription.AcceptsTab = true; 41 | this.TextBoxDescription.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 42 | | System.Windows.Forms.AnchorStyles.Left) 43 | | System.Windows.Forms.AnchorStyles.Right))); 44 | this.TextBoxDescription.Location = new System.Drawing.Point(11, 39); 45 | this.TextBoxDescription.Margin = new System.Windows.Forms.Padding(2); 46 | this.TextBoxDescription.Multiline = true; 47 | this.TextBoxDescription.Name = "TextBoxDescription"; 48 | this.TextBoxDescription.ScrollBars = System.Windows.Forms.ScrollBars.Both; 49 | this.TextBoxDescription.Size = new System.Drawing.Size(421, 73); 50 | this.TextBoxDescription.TabIndex = 4; 51 | // 52 | // BtnSaveButton 53 | // 54 | this.BtnSaveButton.Anchor = System.Windows.Forms.AnchorStyles.Bottom; 55 | this.BtnSaveButton.Location = new System.Drawing.Point(151, 116); 56 | this.BtnSaveButton.Margin = new System.Windows.Forms.Padding(2); 57 | this.BtnSaveButton.Name = "BtnSaveButton"; 58 | this.BtnSaveButton.Size = new System.Drawing.Size(68, 24); 59 | this.BtnSaveButton.TabIndex = 26; 60 | this.BtnSaveButton.Text = "Save"; 61 | this.BtnSaveButton.UseVisualStyleBackColor = true; 62 | this.BtnSaveButton.Click += new System.EventHandler(this.BtnSaveButton_Click); 63 | // 64 | // BtnCancelButton 65 | // 66 | this.BtnCancelButton.Anchor = System.Windows.Forms.AnchorStyles.Bottom; 67 | this.BtnCancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel; 68 | this.BtnCancelButton.Location = new System.Drawing.Point(223, 116); 69 | this.BtnCancelButton.Margin = new System.Windows.Forms.Padding(2); 70 | this.BtnCancelButton.Name = "BtnCancelButton"; 71 | this.BtnCancelButton.Size = new System.Drawing.Size(68, 24); 72 | this.BtnCancelButton.TabIndex = 27; 73 | this.BtnCancelButton.Text = "Cancel"; 74 | this.BtnCancelButton.UseVisualStyleBackColor = true; 75 | // 76 | // labelUpdateIssueNote 77 | // 78 | this.labelUpdateIssueNote.AutoSize = true; 79 | this.labelUpdateIssueNote.Location = new System.Drawing.Point(12, 22); 80 | this.labelUpdateIssueNote.Name = "labelUpdateIssueNote"; 81 | this.labelUpdateIssueNote.Size = new System.Drawing.Size(79, 13); 82 | this.labelUpdateIssueNote.TabIndex = 28; 83 | this.labelUpdateIssueNote.Text = "Additional Note"; 84 | // 85 | // UpdateIssueNoteForm 86 | // 87 | this.AcceptButton = this.BtnSaveButton; 88 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 89 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 90 | this.CancelButton = this.BtnCancelButton; 91 | this.ClientSize = new System.Drawing.Size(443, 151); 92 | this.Controls.Add(this.labelUpdateIssueNote); 93 | this.Controls.Add(this.BtnSaveButton); 94 | this.Controls.Add(this.BtnCancelButton); 95 | this.Controls.Add(this.TextBoxDescription); 96 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; 97 | this.MaximizeBox = false; 98 | this.MinimizeBox = false; 99 | this.Name = "UpdateIssueNoteForm"; 100 | this.ShowIcon = false; 101 | this.ShowInTaskbar = false; 102 | this.Text = "UpdateIssueNoteForm"; 103 | this.Load += new System.EventHandler(this.UpdateIssueNoteForm_Load); 104 | this.ResumeLayout(false); 105 | this.PerformLayout(); 106 | 107 | } 108 | 109 | #endregion 110 | 111 | private System.Windows.Forms.TextBox TextBoxDescription; 112 | private System.Windows.Forms.Button BtnSaveButton; 113 | private System.Windows.Forms.Button BtnCancelButton; 114 | private System.Windows.Forms.Label labelUpdateIssueNote; 115 | } 116 | } -------------------------------------------------------------------------------- /Redmine.Client/UpdateIssueNoteForm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Drawing; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Windows.Forms; 9 | using Redmine.Net.Api.Types; 10 | using Redmine.Client.Languages; 11 | 12 | namespace Redmine.Client 13 | { 14 | public partial class UpdateIssueNoteForm : Form 15 | { 16 | private Issue fromIssue; 17 | private Issue toIssue; 18 | public String Note { get; private set; } 19 | 20 | public UpdateIssueNoteForm(Issue fromIssue, Issue toIssue) 21 | { 22 | this.fromIssue = fromIssue; 23 | this.toIssue = toIssue; 24 | InitializeComponent(); 25 | 26 | this.Text = String.Format(Lang.DlgUpdateIssueNoteTitle, toIssue.Id, toIssue.Subject); 27 | LangTools.UpdateControlsForLanguage(this.Controls); 28 | } 29 | 30 | private void AddUpdatedLabel(string fieldName, string labelCaption) 31 | { 32 | if (String.IsNullOrEmpty(labelCaption)) 33 | return; 34 | Label newLabel = new Label(); 35 | newLabel.AutoSize = true; 36 | newLabel.Location = new System.Drawing.Point(labelUpdateIssueNote.Location.X, labelUpdateIssueNote.Location.Y); 37 | newLabel.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0); 38 | newLabel.Name = "labelUpdateField_" + fieldName; 39 | newLabel.Size = new System.Drawing.Size(44, 13); 40 | newLabel.TabIndex = 4; 41 | newLabel.Text = labelCaption; 42 | newLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); 43 | Controls.Add(newLabel); 44 | if (newLabel.Size.Width > Size.Width - newLabel.Location.X - 10) 45 | this.Size = new Size(newLabel.Location.X + newLabel.Size.Width + 10, this.Size.Height); 46 | 47 | SuspendLayout(); 48 | int newLabelHeight = newLabel.Height + 5; 49 | Size = new System.Drawing.Size(Size.Width, Size.Height + newLabelHeight); 50 | MinimumSize = new System.Drawing.Size(MinimumSize.Width, MinimumSize.Height + newLabelHeight); 51 | labelUpdateIssueNote.MoveControl(0, newLabelHeight); 52 | TextBoxDescription.MoveControl(0, newLabelHeight); 53 | BtnSaveButton.MoveControl(0, newLabelHeight); 54 | BtnCancelButton.MoveControl(0, newLabelHeight); 55 | ResumeLayout(false); 56 | } 57 | 58 | private void UpdateIssueNoteForm_Load(object sender, EventArgs e) 59 | { 60 | AddUpdatedLabel("project", LangTools.CreateUpdatedText("project", fromIssue.Project, toIssue.Project)); 61 | AddUpdatedLabel("tracker", LangTools.CreateUpdatedText("tracker", fromIssue.Tracker, toIssue.Tracker)); 62 | AddUpdatedLabel("subject", LangTools.CreateUpdatedText("subject", fromIssue.Subject, toIssue.Subject)); 63 | AddUpdatedLabel("priority", LangTools.CreateUpdatedText("priority", fromIssue.Priority, toIssue.Priority)); 64 | AddUpdatedLabel("status", LangTools.CreateUpdatedText("status", fromIssue.Status, toIssue.Status)); 65 | AddUpdatedLabel("author", LangTools.CreateUpdatedText("author", fromIssue.Author, toIssue.Author)); 66 | AddUpdatedLabel("assignedto", LangTools.CreateUpdatedText("assignedto", fromIssue.AssignedTo, toIssue.AssignedTo)); 67 | AddUpdatedLabel("category", LangTools.CreateUpdatedText("category", fromIssue.Category, toIssue.Category)); 68 | AddUpdatedLabel("parentissue", LangTools.CreateUpdatedText("parentissue", fromIssue.ParentIssue, toIssue.ParentIssue)); 69 | AddUpdatedLabel("fixedversion", LangTools.CreateUpdatedText("fixedversion", fromIssue.FixedVersion, toIssue.FixedVersion)); 70 | AddUpdatedLabel("start_date", LangTools.CreateUpdatedText("startdate", fromIssue.StartDate, toIssue.StartDate, "d")); 71 | AddUpdatedLabel("duedate", LangTools.CreateUpdatedText("duedate", fromIssue.DueDate, toIssue.DueDate, "d")); 72 | AddUpdatedLabel("doneratio", LangTools.CreateUpdatedText("doneratio", fromIssue.DoneRatio, toIssue.DoneRatio, "0.0")); 73 | AddUpdatedLabel("estimatedhours", LangTools.CreateUpdatedText("estimatedhours", fromIssue.EstimatedHours, toIssue.EstimatedHours, "0.0")); 74 | //AddUpdatedLabel("createdon", LangTools.CreateUpdatedText("createdon", fromIssue.CreatedOn, toIssue.CreatedOn, "d")); 75 | //AddUpdatedLabel("updatedon", LangTools.CreateUpdatedText("updatedon", fromIssue.UpdatedOn, toIssue.UpdatedOn, "d")); 76 | if (fromIssue.Description != toIssue.Description) 77 | AddUpdatedLabel("description", Lang.UpdatedField_Description); 78 | } 79 | 80 | private void BtnSaveButton_Click(object sender, EventArgs e) 81 | { 82 | Note = TextBoxDescription.Text; 83 | this.DialogResult = DialogResult.OK; 84 | this.Close(); 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /Redmine.Client/UpdateIssueNoteForm.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /Redmine.Client/Utility.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.Xml; 5 | using System.Diagnostics; 6 | 7 | namespace Redmine.Client 8 | { 9 | 10 | /// 11 | /// Utility class providing helper functions for the application 12 | /// 13 | internal static class Utility 14 | { 15 | /// 16 | /// URL of the current version XML file 17 | /// 18 | private const string currentVersionXmlUrl = "https://redmine-desktop-client.googlecode.com/svn/tags/releases/latestversion.xml"; 19 | 20 | /// 21 | /// checks for updates 22 | /// 23 | /// url for downloading the latest version or empty string 24 | internal static string CheckForUpdate() 25 | { 26 | try 27 | { 28 | XmlDocument doc = new XmlDocument(); 29 | doc.Load(new XmlTextReader(currentVersionXmlUrl)); 30 | Version latestVersion = new Version(doc.SelectSingleNode("//redmineclient/version").InnerText); 31 | string latestVersionUrl = doc.SelectSingleNode("//redmineclient/url").InnerText; 32 | Version myVersion = new Version(FileVersionInfo.GetVersionInfo(System.Windows.Forms.Application.ExecutablePath).FileVersion); 33 | if (myVersion < latestVersion) 34 | { 35 | return latestVersionUrl; 36 | } 37 | } 38 | catch (Exception) // we do not care about the errors, we will simply try it the next time around 39 | { 40 | } 41 | 42 | return String.Empty; 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Redmine.Client/app.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | my username 12 | 13 | 14 | http://redmine.example.org 15 | 16 | 17 | my password 18 | 19 | 20 | True 21 | 22 | 23 | True 24 | 25 | 26 | True 27 | 28 | 29 | True 30 | 31 | 32 | 0 33 | 34 | 35 | 0 36 | 37 | 38 | 540 39 | 40 | 41 | 460 42 | 43 | 44 | 0 45 | 46 | 47 | 0 48 | 49 | 50 | 0 51 | 52 | 53 | en 54 | 55 | 56 | 3 57 | 58 | 59 | 0 60 | 61 | 62 | False 63 | 64 | 65 | False 66 | 67 | 68 | 0 69 | 70 | 71 | False 72 | 73 | 74 | False 75 | 76 | 77 | 0 78 | 79 | 80 | 0 81 | 82 | 83 | 492 84 | 85 | 86 | 374 87 | 88 | 89 | True 90 | 91 | 92 | None 93 | 94 | 95 | Id 96 | 97 | 98 | False 99 | 100 | 101 | False 102 | 103 | 104 | False 105 | 106 | 107 | False 108 | 109 | 110 | False 111 | 112 | 113 | False 114 | 115 | 116 | False 117 | 118 | 119 | xml 120 | 121 | 122 | True 123 | 124 | 125 | True 126 | 127 | 128 | 129 | 130 | -------------------------------------------------------------------------------- /Redmine.Client/res/aboutclock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheMagician1/redmine-desktop-client/083b23d6247c1d87edd5ed9684dc58fd43f70ed9/Redmine.Client/res/aboutclock.png -------------------------------------------------------------------------------- /Redmine.Client/res/clock-installer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheMagician1/redmine-desktop-client/083b23d6247c1d87edd5ed9684dc58fd43f70ed9/Redmine.Client/res/clock-installer.png -------------------------------------------------------------------------------- /Redmine.Client/res/clock-transparant.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheMagician1/redmine-desktop-client/083b23d6247c1d87edd5ed9684dc58fd43f70ed9/Redmine.Client/res/clock-transparant.png -------------------------------------------------------------------------------- /Redmine.Client/res/clock.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheMagician1/redmine-desktop-client/083b23d6247c1d87edd5ed9684dc58fd43f70ed9/Redmine.Client/res/clock.ico -------------------------------------------------------------------------------- /Redmine.Client/res/clock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheMagician1/redmine-desktop-client/083b23d6247c1d87edd5ed9684dc58fd43f70ed9/Redmine.Client/res/clock.png -------------------------------------------------------------------------------- /RedmineClient.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.25123.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Redmine.Client", "Redmine.Client\Redmine.Client.csproj", "{07ABD877-B270-4054-B10E-7AA4DEBD37E0}" 7 | EndProject 8 | Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "Setup", "Setup\Setup.wixproj", "{CAE8E32C-D717-4ED3-A795-C5D10FDBE64E}" 9 | ProjectSection(ProjectDependencies) = postProject 10 | {07ABD877-B270-4054-B10E-7AA4DEBD37E0} = {07ABD877-B270-4054-B10E-7AA4DEBD37E0} 11 | EndProjectSection 12 | EndProject 13 | Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "Installer", "Installer\Installer.wixproj", "{DE8A1716-DEA3-4CEA-83E5-D24D94519B45}" 14 | EndProject 15 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "redmine-net451-api", "Redmine.Api\redmine-net451-api\redmine-net451-api.csproj", "{4AB94C09-8CFB-41C6-87D1-6B972E7F9307}" 16 | EndProject 17 | Global 18 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 19 | Debug|Any CPU = Debug|Any CPU 20 | Debug|Mixed Platforms = Debug|Mixed Platforms 21 | Debug|x86 = Debug|x86 22 | Release|Any CPU = Release|Any CPU 23 | Release|Mixed Platforms = Release|Mixed Platforms 24 | Release|x86 = Release|x86 25 | EndGlobalSection 26 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 27 | {07ABD877-B270-4054-B10E-7AA4DEBD37E0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 28 | {07ABD877-B270-4054-B10E-7AA4DEBD37E0}.Debug|Any CPU.Build.0 = Debug|Any CPU 29 | {07ABD877-B270-4054-B10E-7AA4DEBD37E0}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU 30 | {07ABD877-B270-4054-B10E-7AA4DEBD37E0}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU 31 | {07ABD877-B270-4054-B10E-7AA4DEBD37E0}.Debug|x86.ActiveCfg = Debug|Any CPU 32 | {07ABD877-B270-4054-B10E-7AA4DEBD37E0}.Debug|x86.Build.0 = Debug|Any CPU 33 | {07ABD877-B270-4054-B10E-7AA4DEBD37E0}.Release|Any CPU.ActiveCfg = Release|Any CPU 34 | {07ABD877-B270-4054-B10E-7AA4DEBD37E0}.Release|Any CPU.Build.0 = Release|Any CPU 35 | {07ABD877-B270-4054-B10E-7AA4DEBD37E0}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU 36 | {07ABD877-B270-4054-B10E-7AA4DEBD37E0}.Release|Mixed Platforms.Build.0 = Release|Any CPU 37 | {07ABD877-B270-4054-B10E-7AA4DEBD37E0}.Release|x86.ActiveCfg = Release|Any CPU 38 | {07ABD877-B270-4054-B10E-7AA4DEBD37E0}.Release|x86.Build.0 = Release|Any CPU 39 | {CAE8E32C-D717-4ED3-A795-C5D10FDBE64E}.Debug|Any CPU.ActiveCfg = Debug|x86 40 | {CAE8E32C-D717-4ED3-A795-C5D10FDBE64E}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 41 | {CAE8E32C-D717-4ED3-A795-C5D10FDBE64E}.Debug|Mixed Platforms.Build.0 = Debug|x86 42 | {CAE8E32C-D717-4ED3-A795-C5D10FDBE64E}.Debug|x86.ActiveCfg = Debug|x86 43 | {CAE8E32C-D717-4ED3-A795-C5D10FDBE64E}.Debug|x86.Build.0 = Debug|x86 44 | {CAE8E32C-D717-4ED3-A795-C5D10FDBE64E}.Release|Any CPU.ActiveCfg = Release|x86 45 | {CAE8E32C-D717-4ED3-A795-C5D10FDBE64E}.Release|Mixed Platforms.ActiveCfg = Release|x86 46 | {CAE8E32C-D717-4ED3-A795-C5D10FDBE64E}.Release|Mixed Platforms.Build.0 = Release|x86 47 | {CAE8E32C-D717-4ED3-A795-C5D10FDBE64E}.Release|x86.ActiveCfg = Release|x86 48 | {CAE8E32C-D717-4ED3-A795-C5D10FDBE64E}.Release|x86.Build.0 = Release|x86 49 | {DE8A1716-DEA3-4CEA-83E5-D24D94519B45}.Debug|Any CPU.ActiveCfg = Debug|x86 50 | {DE8A1716-DEA3-4CEA-83E5-D24D94519B45}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 51 | {DE8A1716-DEA3-4CEA-83E5-D24D94519B45}.Debug|Mixed Platforms.Build.0 = Debug|x86 52 | {DE8A1716-DEA3-4CEA-83E5-D24D94519B45}.Debug|x86.ActiveCfg = Debug|x86 53 | {DE8A1716-DEA3-4CEA-83E5-D24D94519B45}.Debug|x86.Build.0 = Debug|x86 54 | {DE8A1716-DEA3-4CEA-83E5-D24D94519B45}.Release|Any CPU.ActiveCfg = Release|x86 55 | {DE8A1716-DEA3-4CEA-83E5-D24D94519B45}.Release|Mixed Platforms.ActiveCfg = Release|x86 56 | {DE8A1716-DEA3-4CEA-83E5-D24D94519B45}.Release|Mixed Platforms.Build.0 = Release|x86 57 | {DE8A1716-DEA3-4CEA-83E5-D24D94519B45}.Release|x86.ActiveCfg = Release|x86 58 | {DE8A1716-DEA3-4CEA-83E5-D24D94519B45}.Release|x86.Build.0 = Release|x86 59 | {4AB94C09-8CFB-41C6-87D1-6B972E7F9307}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 60 | {4AB94C09-8CFB-41C6-87D1-6B972E7F9307}.Debug|Any CPU.Build.0 = Debug|Any CPU 61 | {4AB94C09-8CFB-41C6-87D1-6B972E7F9307}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU 62 | {4AB94C09-8CFB-41C6-87D1-6B972E7F9307}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU 63 | {4AB94C09-8CFB-41C6-87D1-6B972E7F9307}.Debug|x86.ActiveCfg = Debug|Any CPU 64 | {4AB94C09-8CFB-41C6-87D1-6B972E7F9307}.Debug|x86.Build.0 = Debug|Any CPU 65 | {4AB94C09-8CFB-41C6-87D1-6B972E7F9307}.Release|Any CPU.ActiveCfg = Release|Any CPU 66 | {4AB94C09-8CFB-41C6-87D1-6B972E7F9307}.Release|Any CPU.Build.0 = Release|Any CPU 67 | {4AB94C09-8CFB-41C6-87D1-6B972E7F9307}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU 68 | {4AB94C09-8CFB-41C6-87D1-6B972E7F9307}.Release|Mixed Platforms.Build.0 = Release|Any CPU 69 | {4AB94C09-8CFB-41C6-87D1-6B972E7F9307}.Release|x86.ActiveCfg = Release|Any CPU 70 | {4AB94C09-8CFB-41C6-87D1-6B972E7F9307}.Release|x86.Build.0 = Release|Any CPU 71 | EndGlobalSection 72 | GlobalSection(SolutionProperties) = preSolution 73 | HideSolutionNode = FALSE 74 | EndGlobalSection 75 | GlobalSection(SubversionScc) = preSolution 76 | Svn-Managed = True 77 | Manager = AnkhSVN - Subversion Support for Visual Studio 78 | EndGlobalSection 79 | EndGlobal 80 | -------------------------------------------------------------------------------- /Setup/Banner.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheMagician1/redmine-desktop-client/083b23d6247c1d87edd5ed9684dc58fd43f70ed9/Setup/Banner.bmp -------------------------------------------------------------------------------- /Setup/Dialog.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheMagician1/redmine-desktop-client/083b23d6247c1d87edd5ed9684dc58fd43f70ed9/Setup/Dialog.bmp -------------------------------------------------------------------------------- /Setup/License.RedmineClient.rtf: -------------------------------------------------------------------------------- 1 | {\rtf1\ansi\deff3\adeflang1025 2 | {\fonttbl{\f0\froman\fprq2\fcharset0 Times New Roman;}{\f1\froman\fprq2\fcharset2 Symbol;}{\f2\fswiss\fprq2\fcharset0 Arial;}{\f3\froman\fprq2\fcharset0 Liberation Serif{\*\falt Times New Roman};}{\f4\fswiss\fprq2\fcharset0 Liberation Sans{\*\falt Arial};}{\f5\froman\fprq0\fcharset128 Tahoma;}{\f6\froman\fprq0\fcharset128 Calibri;}{\f7\fnil\fprq2\fcharset0 Microsoft YaHei;}{\f8\fnil\fprq2\fcharset0 Mangal;}{\f9\fnil\fprq0\fcharset128 Mangal;}} 3 | {\colortbl;\red0\green0\blue0;\red128\green128\blue128;} 4 | {\stylesheet{\s0\snext0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af10\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang1043 Normal;} 5 | {\s15\sbasedon0\snext16\sb240\sa120\keepn\dbch\af7\dbch\af8\afs28\loch\f4\fs28 Heading;} 6 | {\s16\sbasedon0\snext16\sl288\slmult1\sb0\sa140 Text Body;} 7 | {\s17\sbasedon16\snext17\sl288\slmult1\sb0\sa140\dbch\af9 List;} 8 | {\s18\sbasedon0\snext18\sb120\sa120\noline\i\dbch\af9\afs24\ai\fs24 Caption;} 9 | {\s19\sbasedon0\snext19\noline\dbch\af9 Index;} 10 | }{\info{\creatim\yr0\mo0\dy0\hr0\min0}{\revtim\yr0\mo0\dy0\hr0\min0}{\printim\yr0\mo0\dy0\hr0\min0}{\comment LibreOffice}{\vern67241475}}\deftab708 11 | \viewscale100 12 | {\*\pgdsctbl 13 | {\pgdsc0\pgdscuse451\pgwsxn12240\pghsxn15840\marglsxn1800\margrsxn1800\margtsxn1440\margbsxn1440\pgdscnxt0 Default Style;}} 14 | \formshade{\*\pgdscno0}\paperh15840\paperw12240\margl1800\margr1800\margt1440\margb1440\sectd\sbknone\sectunlocked1\pgndec\pgwsxn12240\pghsxn15840\marglsxn1800\margrsxn1800\margtsxn1440\margbsxn1440\ftnbj\ftnstart1\ftnrstcont\ftnnar\aenddoc\aftnrstcont\aftnstart1\aftnnrlc 15 | \pgndec\pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af10\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang1043{\rtlch \ltrch\loch\fs17\lang1033\loch\f5 16 | Redmine Desktop Client} 17 | \par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af10\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang1043{\rtlch \ltrch\loch\fs17\lang1033\loch\f5 18 | =========} 19 | \par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af10\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang1043\rtlch \ltrch\loch\fs17\lang1033\loch\f5 20 | 21 | \par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af10\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang1043{{\*\bkmkstart __DdeLink__14_824045980}{\*\bkmkend __DdeLink__14_824045980}\rtlch \ltrch\loch\fs17\lang1033\loch\f5 22 | Desktop tool for reporting time spent on issues in Redmine project management system.} 23 | \par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af10\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang1043\rtlch \ltrch\loch\fs17\lang1033\loch\f5 24 | 25 | \par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af10\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang1043{\rtlch \ltrch\loch\fs17\lang1033\loch\f5 26 | You can download it, report bugs, get the source or post feature requests on }{\rtlch \ltrch\loch\fs17\lang1033\loch\f5 27 | https://github.com/TheMagician1/redmine-desktop-client} 28 | \par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af10\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang1043{\*\bkmkstart __DdeLink__14_824045980}{\*\bkmkend __DdeLink__14_824045980}{\*\bkmkstart __DdeLink__14_824045980}{\*\bkmkend __DdeLink__14_824045980}\rtlch \ltrch\loch\fs17\lang1033\loch\f5 29 | 30 | \par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af10\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang1043{\rtlch \ltrch\loch\fs17\lang1033\loch\f5 31 | You are free to use this code as much as you wish, but if you make any improvemens, please share them with the community.} 32 | \par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af10\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang1043\rtlch \ltrch\loch\fs17\lang1033\loch\f5 33 | 34 | \par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af10\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang1043{\rtlch \ltrch\loch\fs17\lang1033\loch\f5 35 | Icons from the excellent Nuvola theme drawn by David Vignoni.} 36 | \par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af10\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang1043\rtlch \ltrch\loch\fs17\lang1033\loch\f5 37 | 38 | \par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af10\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang1043{\rtlch \ltrch\loch\fs17\lang1033\loch\f5 39 | Copyright (c) 2009, Pavel Kalian} 40 | \par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af10\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang1043{\rtlch \ltrch\loch\fs17\lang1033\loch\f5 41 | Copyright (c) 2012, Bas van Leeuwen} 42 | \par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af10\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang1043{\rtlch \ltrch\loch\fs17\lang1033\loch\f5 43 | All rights reserved.} 44 | \par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af10\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang1043\rtlch \ltrch\loch\fs17\lang1033\loch\f5 45 | 46 | \par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af10\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang1043{\rtlch \ltrch\loch\fs17\lang1033\loch\f5 47 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:} 48 | \par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af10\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang1043\rtlch \ltrch\loch\fs17\lang1033\loch\f5 49 | 50 | \par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af10\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang1043{\rtlch \ltrch\fs17\lang1033\loch\f5 51 | }{\rtlch \ltrch\loch\fs17\lang1033\loch\f5 52 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.} 53 | \par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af10\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang1043{\rtlch \ltrch\fs17\lang1033\loch\f5 54 | }{\rtlch \ltrch\loch\fs17\lang1033\loch\f5 55 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.} 56 | \par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af10\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang1043{\rtlch \ltrch\fs17\lang1033\loch\f5 57 | }{\rtlch \ltrch\loch\fs17\lang1033\loch\f5 58 | * Neither the name of the author nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.} 59 | \par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af10\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang1043\rtlch \ltrch\loch\fs17\lang1033\loch\f5 60 | 61 | \par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af10\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang1043{\rtlch \ltrch\loch\fs17\lang1033\loch\f5 62 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.} 63 | \par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af10\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang1043\sl276\slmult1\sb0\sa200\rtlch \ltrch\loch 64 | 65 | \par } -------------------------------------------------------------------------------- /Setup/Setup.wixproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | x86 6 | 3.5 7 | {cae8e32c-d717-4ed3-a795-c5d10fdbe64e} 8 | 2.0 9 | RedmineClientSetup 10 | Package 11 | $(MSBuildExtensionsPath32)\Microsoft\WiX\v3.x\Wix.targets 12 | $(MSBuildExtensionsPath)\Microsoft\WiX\v3.x\Wix.targets 13 | Setup 14 | 15 | 16 | bin\$(Configuration)\ 17 | obj\$(Configuration)\ 18 | Debug 19 | 20 | 21 | bin\$(Configuration)\ 22 | obj\$(Configuration)\ 23 | 24 | 25 | 26 | 27 | 28 | 29 | $(WixExtDir)\WixUIExtension.dll 30 | WixUIExtension 31 | 32 | 33 | $(WixExtDir)\WixNetFxExtension.dll 34 | WixNetFxExtension 35 | 36 | 37 | 38 | 39 | redmine-net40-api 40 | {0d9b763c-a16b-463b-bddd-0a0467dcd32e} 41 | True 42 | True 43 | Binaries;Content;Satellites 44 | INSTALLFOLDER 45 | 46 | 47 | Redmine.Client 48 | {07abd877-b270-4054-b10e-7aa4debd37e0} 49 | True 50 | True 51 | Binaries;Content;Satellites 52 | INSTALLFOLDER 53 | 54 | 55 | 56 | 66 | 67 | 68 | --------------------------------------------------------------------------------