TimeSheetForm.cs
  1. //
  2. // This code is part of Document Solutions for PDF demos.
  3. // Copyright (c) MESCIUS inc. All rights reserved.
  4. //
  5. using System;
  6. using System.IO;
  7. using System.Linq;
  8. using System.Drawing;
  9. using System.Collections.Generic;
  10. using GrapeCity.Documents.Pdf;
  11. using GrapeCity.Documents.Pdf.AcroForms;
  12. using GrapeCity.Documents.Text;
  13. using GrapeCity.Documents.Common;
  14. using GrapeCity.Documents.Drawing;
  15. using System.Security.Cryptography.X509Certificates;
  16. using GCTEXT = GrapeCity.Documents.Text;
  17. using GCDRAW = GrapeCity.Documents.Drawing;
  18.  
  19. namespace DsPdfWeb.Demos
  20. {
  21. // This sample generates a PDF AcroForm representing a time sheet.
  22. // The same code is used to generate the time sheet in the TimeSheet use case sample.
  23. public class TimeSheetForm
  24. {
  25. // Font collection to hold the fonts we need:
  26. private FontCollection _fc = new FontCollection();
  27. // The text layout used to render input fields when flattening the document:
  28. private TextLayout _inputTl = new TextLayout(72);
  29. // The text format used for input fields:
  30. private GCTEXT.Font _inputFont = FontCollection.SystemFonts.FindFamilyName("Segoe UI", true);
  31. private float _inputFontSize = 12;
  32. // Input fields margin:
  33. private float _inputMargin = 5;
  34. // Space for employee's signature:
  35. private RectangleF _empSignRect;
  36. // Logo (we should dispose it after saving the document):
  37. private GCDRAW.Image _logo = null;
  38.  
  39. // Main entry point of this sample:
  40. public int CreatePDF(Stream stream)
  41. {
  42. // Set up a font collection with the fonts we need:
  43. _fc.RegisterDirectory(Path.Combine("Resources", "Fonts"));
  44. // Set that font collection on input fields' text layout
  45. // (we will also set it on all text layouts that we'll use):
  46. _inputTl.FontCollection = _fc;
  47. // Set up layout and formatting for input fields:
  48. _inputTl.ParagraphAlignment = ParagraphAlignment.Center;
  49.  
  50. // Create the time sheet input form
  51. // (in a real-life scenario, we probably would only create it once,
  52. // and then re-use the form PDF):
  53. var doc = MakeTimeSheetForm();
  54. // Save the PDF:
  55. doc.Save(stream);
  56. // Images used in a document can be disposed only after saving the PDF:
  57. _logo.Dispose();
  58. // Done:
  59. return doc.Pages.Count;
  60. }
  61.  
  62. // Data field names:
  63. static class _Names
  64. {
  65. public static readonly string[] Dows = new string[]
  66. {
  67. "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",
  68. };
  69. public const string EmpName = "empName";
  70. public const string EmpTitle = "empTitle";
  71. public const string EmpNum = "empNum";
  72. public const string EmpStatus = "empStatus";
  73. public const string EmpDep = "empDep";
  74. public const string EmpSuper = "empSuper";
  75. public static Dictionary<string, string[]> DtNames = new Dictionary<string, string[]>()
  76. {
  77. {"Sun", new string[] { "dtSun", "tSunStart", "tSunEnd", "tSunReg", "tSunOvr", "tSunTotal" } },
  78. {"Mon", new string[] { "dtMon", "tMonStart", "tMonEnd", "tMonReg", "tMonOvr", "tMonTotal" } },
  79. {"Tue", new string[] { "dtTue", "tTueStart", "tTueEnd", "tTueReg", "tTueOvr", "tTueTotal" } },
  80. {"Wed", new string[] { "dtWed", "tWedStart", "tWedEnd", "tWedReg", "tWedOvr", "tWedTotal" } },
  81. {"Thu", new string[] { "dtThu", "tThuStart", "tThuEnd", "tThuReg", "tThuOvr", "tThuTotal" } },
  82. {"Fri", new string[] { "dtFri", "tFriStart", "tFriEnd", "tFriReg", "tFriOvr", "tFriTotal" } },
  83. {"Sat", new string[] { "dtSat", "tSatStart", "tSatEnd", "tSatReg", "tSatOvr", "tSatTotal" } },
  84. };
  85. public const string TotalReg = "totReg";
  86. public const string TotalOvr = "totOvr";
  87. public const string TotalHours = "totHours";
  88. public const string EmpSign = "empSign";
  89. public const string EmpSignDate = "empSignDate";
  90. public const string SupSign = "supSign";
  91. public const string SupSignDate = "supSignDate";
  92. }
  93.  
  94. // Creates the Time Sheet form:
  95. private GcPdfDocument MakeTimeSheetForm()
  96. {
  97. const float marginH = 72, marginV = 48;
  98. var doc = new GcPdfDocument();
  99. var page = doc.NewPage();
  100. var g = page.Graphics;
  101. var ip = new PointF(marginH, marginV);
  102.  
  103. var tl = new TextLayout(g.Resolution) { FontCollection = _fc };
  104.  
  105. tl.Append("TIME SHEET", new TextFormat() { FontName = "Segoe UI", FontSize = 18 });
  106. tl.PerformLayout(true);
  107. g.DrawTextLayout(tl, ip);
  108. ip.Y += tl.ContentHeight + 15;
  109.  
  110. _logo = GCDRAW.Image.FromFile(Path.Combine("Resources", "ImagesBis", "AcmeLogo-vertical-250px.png"));
  111. var s = new SizeF(250f * 0.75f, 64f * 0.75f);
  112. g.DrawImage(_logo, new RectangleF(ip, s), null, ImageAlign.Default);
  113. ip.Y += s.Height + 5;
  114.  
  115. tl.Clear();
  116. tl.Append("Where Business meets Technology",
  117. new TextFormat() { FontName = "Segoe UI", FontItalic = true, FontSize = 10 });
  118. tl.PerformLayout(true);
  119. g.DrawTextLayout(tl, ip);
  120. ip.Y += tl.ContentHeight + 15;
  121.  
  122. tl.Clear();
  123. tl.Append("1901, Halford Avenue,\r\nSanta Clara, California – 95051-2553,\r\nUnited States",
  124. new TextFormat() { FontName = "Segoe UI", FontSize = 9 });
  125. tl.MaxWidth = page.Size.Width - marginH * 2;
  126. tl.TextAlignment = TextAlignment.Trailing;
  127. tl.PerformLayout(true);
  128. g.DrawTextLayout(tl, ip);
  129. ip.Y += tl.ContentHeight + 25;
  130.  
  131. var pen = new GCDRAW.Pen(Color.Gray, 0.5f);
  132.  
  133. var colw = (page.Size.Width - marginH * 2) / 2;
  134. var fields1 = DrawTable(ip,
  135. new float[] { colw, colw },
  136. new float[] { 30, 30, 30 },
  137. g, pen);
  138.  
  139. var tf = new TextFormat() { FontName = "Segoe UI", FontSize = 9 };
  140. tl.ParagraphAlignment = ParagraphAlignment.Center;
  141. tl.TextAlignment = TextAlignment.Leading;
  142. tl.MarginLeft = tl.MarginRight = tl.MarginTop = tl.MarginBottom = 4;
  143. // t_ - caption
  144. // b_ - bounds
  145. // f_ - field name, null means no field
  146. Action<string, RectangleF, string> drawField = (t_, b_, f_) =>
  147. {
  148. float tWidth;
  149. if (!string.IsNullOrEmpty(t_))
  150. {
  151. tl.Clear();
  152. tl.MaxHeight = b_.Height;
  153. tl.MaxWidth = b_.Width;
  154. tl.Append(t_, tf);
  155. tl.PerformLayout(true);
  156. g.DrawTextLayout(tl, b_.Location);
  157. tWidth = tl.ContentRectangle.Right;
  158. }
  159. else
  160. tWidth = 0;
  161. if (!string.IsNullOrEmpty(f_))
  162. {
  163. var fld = new TextField() { Name = f_ };
  164. fld.Widget.Page = page;
  165. fld.Widget.Rect = new RectangleF(
  166. b_.X + tWidth + _inputMargin, b_.Y + _inputMargin,
  167. b_.Width - tWidth - _inputMargin * 2, b_.Height - _inputMargin * 2);
  168. fld.Widget.DefaultAppearance.Font = _inputFont;
  169. fld.Widget.DefaultAppearance.FontSize = _inputFontSize;
  170. fld.Widget.Border.Color = Color.LightSlateGray;
  171. fld.Widget.Border.Width = 0.5f;
  172. doc.AcroForm.Fields.Add(fld);
  173. }
  174. };
  175.  
  176. drawField("EMPLOYEE NAME: ", fields1[0, 0], _Names.EmpName);
  177. drawField("TITLE: ", fields1[1, 0], _Names.EmpTitle);
  178. drawField("EMPLOYEE NUMBER: ", fields1[0, 1], _Names.EmpNum);
  179. drawField("STATUS: ", fields1[1, 1], _Names.EmpStatus);
  180. drawField("DEPARTMENT: ", fields1[0, 2], _Names.EmpDep);
  181. drawField("SUPERVISOR: ", fields1[1, 2], _Names.EmpSuper);
  182.  
  183. ip.Y = fields1[0, 2].Bottom;
  184.  
  185. float col0 = 100;
  186. colw = (page.Size.Width - marginH * 2 - col0) / 5;
  187. float rowh = 25;
  188. var fields2 = DrawTable(ip,
  189. new float[] { col0, colw, colw, colw, colw, colw },
  190. new float[] { 50, rowh, rowh, rowh, rowh, rowh, rowh, rowh, rowh },
  191. g, pen);
  192.  
  193. tl.ParagraphAlignment = ParagraphAlignment.Far;
  194. drawField("DATE", fields2[0, 0], null);
  195. drawField("START TIME", fields2[1, 0], null);
  196. drawField("END TIME", fields2[2, 0], null);
  197. drawField("REGULAR HOURS", fields2[3, 0], null);
  198. drawField("OVERTIME HOURS", fields2[4, 0], null);
  199. tf.FontBold = true;
  200. drawField("TOTAL HOURS", fields2[5, 0], null);
  201. tf.FontBold = false;
  202. tl.ParagraphAlignment = ParagraphAlignment.Center;
  203. tf.ForeColor = Color.Gray;
  204. for (int i = 0; i < 7; ++i)
  205. drawField(_Names.Dows[i], fields2[0, i + 1], _Names.DtNames[_Names.Dows[i]][0]);
  206. // Vertically align date fields (compensate for different DOW widths):
  207. var dowFields = doc.AcroForm.Fields.TakeLast(7);
  208. var minW = dowFields.Min(f_ => ((TextField)f_).Widget.Rect.Width);
  209. dowFields.ToList().ForEach(f_ =>
  210. {
  211. var r_ = ((TextField)f_).Widget.Rect;
  212. r_.Offset(r_.Width - minW, 0);
  213. r_.Width = minW;
  214. ((TextField)f_).Widget.Rect = r_;
  215. });
  216.  
  217. tf.ForeColor = Color.Black;
  218. for (int row = 1; row <= 7; ++row)
  219. for (int col = 1; col <= 5; ++col)
  220. drawField(null, fields2[col, row], _Names.DtNames[_Names.Dows[row - 1]][col]);
  221.  
  222. tf.FontBold = true;
  223. drawField("WEEKLY TOTALS", fields2[0, 8], null);
  224. tf.FontBold = false;
  225.  
  226. drawField(null, fields2[3, 8], _Names.TotalReg);
  227. drawField(null, fields2[4, 8], _Names.TotalOvr);
  228. drawField(null, fields2[5, 8], _Names.TotalHours);
  229.  
  230. ip.Y = fields2[0, 8].Bottom;
  231.  
  232. col0 = 72 * 4;
  233. colw = page.Size.Width - marginH * 2 - col0;
  234. var fields3 = DrawTable(ip,
  235. new float[] { col0, colw },
  236. new float[] { rowh + 10, rowh, rowh },
  237. g, pen);
  238.  
  239. drawField("EMPLOYEE SIGNATURE: ", fields3[0, 1], null);
  240. var r = fields3[0, 1];
  241. _empSignRect = new RectangleF(r.X + r.Width / 2, r.Y, r.Width / 2 - _inputMargin * 2, r.Height);
  242. SignatureField sfEmp = new SignatureField();
  243. sfEmp.Name = _Names.EmpSign;
  244. sfEmp.Widget.Rect = new RectangleF(r.X + r.Width / 2, r.Y + _inputMargin, r.Width / 2 - _inputMargin * 2, r.Height - _inputMargin * 2);
  245. sfEmp.Widget.Page = page;
  246. sfEmp.Widget.BackColor = Color.LightSeaGreen;
  247. doc.AcroForm.Fields.Add(sfEmp);
  248. drawField("DATE: ", fields3[1, 1], _Names.EmpSignDate);
  249.  
  250. drawField("SUPERVISOR SIGNATURE: ", fields3[0, 2], null);
  251. r = fields3[0, 2];
  252. SignatureField sfSup = new SignatureField();
  253. sfSup.Name = _Names.SupSign;
  254. sfSup.Widget.Rect = new RectangleF(r.X + r.Width / 2, r.Y + _inputMargin, r.Width / 2 - _inputMargin * 2, r.Height - _inputMargin * 2);
  255. sfSup.Widget.Page = page;
  256. sfSup.Widget.BackColor = Color.LightYellow;
  257. doc.AcroForm.Fields.Add(sfSup);
  258. drawField("DATE: ", fields3[1, 2], _Names.SupSignDate);
  259.  
  260. // Done:
  261. return doc;
  262. }
  263.  
  264. // Simple table drawing method. Returns the array of table cell rectangles.
  265. private RectangleF[,] DrawTable(PointF loc, float[] widths, float[] heights, GcGraphics g, GCDRAW.Pen p)
  266. {
  267. if (widths.Length == 0 || heights.Length == 0)
  268. throw new Exception("Table must have some columns and rows.");
  269.  
  270. RectangleF[,] cells = new RectangleF[widths.Length, heights.Length];
  271. var r = new RectangleF(loc, new SizeF(widths.Sum(), heights.Sum()));
  272. // Draw left borders (except for 1st one):
  273. float x = loc.X;
  274. for (int i = 0; i < widths.Length; ++i)
  275. {
  276. for (int j = 0; j < heights.Length; ++j)
  277. {
  278. cells[i, j].X = x;
  279. cells[i, j].Width = widths[i];
  280. }
  281. if (i > 0)
  282. g.DrawLine(x, r.Top, x, r.Bottom, p);
  283. x += widths[i];
  284. }
  285. // Draw top borders (except for 1st one):
  286. float y = loc.Y;
  287. for (int j = 0; j < heights.Length; ++j)
  288. {
  289. for (int i = 0; i < widths.Length; ++i)
  290. {
  291. cells[i, j].Y = y;
  292. cells[i, j].Height = heights[j];
  293. }
  294. if (j > 0)
  295. g.DrawLine(r.Left, y, r.Right, y, p);
  296. y += heights[j];
  297. }
  298. // Draw outer border:
  299. g.DrawRectangle(r, p);
  300. // Done:
  301. return cells;
  302. }
  303. }
  304. }
  305.