/* * Table time: * Create a monthly time sheet for the working hours of an employee * * Create a table with one row for each day of the month. Each row has several * columns representing various projects. In a cell the working hours for one or * more tasks are added, related to the respective day and project. * * Required software: PDFlib/PDFlib+PDI/PPS 9 * Required data: none */ package com.pdflib.cookbook.pdflib.table; import com.pdflib.pdflib; import com.pdflib.PDFlibException; public class table_timesheet { public static void main (String argv[]) { /* This is where the data files are. Adjust as necessary. */ String searchpath = "../input"; String outfile = "table_timesheet.pdf"; String title = "Table Time Sheet"; pdflib p = null; int row, col, tf=-1, tbl=-1; int i, j, regularfont, boldfont; String tlcell_opts; String fittab_opts, tfcell_opts; String result; final double pagewidth = 842, pageheight = 595; final double fontsize = 12; final double capheight = 8.5; final int margin = 4; final double rwfirst = 16, rwother = 32; final String leading = "120%"; final int dbreak = 15; /* The table coordinates are fixed */ final int llx = 50, urx = (int) pagewidth - llx; final int lly = 30, ury = (int) pageheight - lly; final double tablewidth = urx - llx; double cwsum = 0; final int yoffset = 10; final int yheading = ury + yoffset; final int ycontinued = lly - yoffset; /* The widths of the first two columns */ final double cwfirst = 50; final int maxdays = 31; int exitcode = 0; /* Projects */ final String projects [] = { "Project 1", "Project 2", "Project 3", "Project 4", "Project 5" }; /* For the first five days of the month entries are made in the timesheet * for each of the projects defined above */ final String times [][] = { /* Project 1, Project 2, Project 3, Project 4, Project 5 */ { "5h task-001", "2h task-033", "", "", "1h task-024" }, { "2h task-354, 2h task-099, 2h task-045, 1h task-001, 1h task-270", "", "", "", "" }, { "", "2h task-354", "4h task-033", "2h task-001", "" }, { "8h task-001", "", "", "", "" }, { "", "2h task-033", "5h task-045, 2h task-024, 0.5h task-033", "", "" } }; try { p = new pdflib(); p.set_option("searchpath={" + searchpath + "}"); /* This means we must check return values of load_font() etc. */ p.set_option("errorpolicy=return"); if (p.begin_document(outfile, "") == -1) throw new Exception("Error: " + p.get_errmsg()); p.set_info("Creator", "PDFlib Cookbook"); p.set_info("Title", title); /* Load the bold and regular styles of a font */ boldfont = p.load_font("Helvetica-Bold", "unicode", ""); if (boldfont == -1) throw new Exception("Error: " + p.get_errmsg()); regularfont = p.load_font("Helvetica", "unicode", ""); if (regularfont == -1) throw new Exception("Error: " + p.get_errmsg()); /* Start the output page */ p.begin_page_ext(pagewidth, pageheight, ""); /* Output the heading */ p.setfont(boldfont, fontsize); p.fit_textline("Time Sheet", llx, yheading, ""); /* ----------------------------------------------------------------- * In the first row, add the text line cells containing the headings * ----------------------------------------------------------------- */ col = 1; row = 1; /* Prepare the option list: * "colwidth" defines a fixed column width. * "rowheight" defines a fixed row height. * "margin" adds some empty space between the text and the cell borders. */ tlcell_opts = "fittextline={font=" + boldfont + " fontsize={capheight=" + capheight + "} position={left top}} " + " colwidth=" + cwfirst + " rowheight=" + rwfirst + " margin=" + margin; /* Add the "Day" heading */ tbl = p.add_table_cell(tbl, col++, row, "Day", tlcell_opts); if (tbl == -1) throw new Exception("Error adding cell: " + p.get_errmsg()); cwsum += cwfirst; /* Add the "hours" heading */ tbl = p.add_table_cell(tbl, col++, row, "Hours", tlcell_opts); if (tbl == -1) throw new Exception("Error adding cell: " + p.get_errmsg()); cwsum += cwfirst; /* Add the project headings. Those columns evenly share the remaining * width of the table's fitbox. */ for (i = 0; i < projects.length; i++) { tlcell_opts = "fittextline={font=" + boldfont + " fontsize={capheight=" + capheight + "} position={left top}}" + " rowheight=" + rwfirst + " colwidth=" + ((tablewidth - cwsum) / projects.length) + " margin=" + margin; tbl = p.add_table_cell(tbl, col++, row, projects[i], tlcell_opts); if (tbl == -1) throw new Exception("Error adding cell: " + p.get_errmsg()); } /* -------------------------------------------------------------- * In the first column add the text line cells containing the day * -------------------------------------------------------------- */ col = 1; row = 2; /* Loop over all days */ for (i = 1; i <= maxdays; i++) { /* Prepare the option list for adding the text line cell */ tlcell_opts = "fittextline={font=" + boldfont + " fontsize={capheight=" + capheight + "} position={left top}} " + " colwidth=" + cwfirst + " rowheight=" + rwother + " margin=" + margin; /* We want to spread the table over two pages. The last row placed * on the first page should be the one representing a defined day, * e.g. the 15th. To accomplish this use the "return" * option of add_table_cell() when adding the respective cell. This * signals to fit_table() to return after having placed the * corresponding table row, and we can fit the following table rows * in a subsequent call on the second page. */ if (i == dbreak) tlcell_opts += " return break"; /* Add the text line cell */ tbl = p.add_table_cell(tbl, col, row++, i + ".", tlcell_opts); if (tbl == -1) throw new Exception("Error adding cell: " + p.get_errmsg()); } /* ------------------------------------------------------------------- * Add the Textflow cell containing the individual times spent for the * different projects * ------------------------------------------------------------------- */ col = 3; row = 2; /* Prepare the option list for adding a Textflow. * "leading" specifies the distance between to text lines. */ final String tf_opts = "font=" + regularfont + " fontsize={capheight=" + capheight + "} leading=" + leading; for (i = 0; i < times.length; i++) { for (j = 0; j < times[i].length; j++) { /* Add the Textflow */ tf = p.add_textflow(-1, times[i][j], tf_opts); if (tf == -1) throw new Exception("Error: " + p.get_errmsg()); /* Prepare the option list for adding the Textflow cell * The first line of the Textflow should be aligned with the * baseline of the text lines. At the same time, the text lines * should have the same distance from the top cell border as the * Textflow. To avoid any space from the top add the Textflow * cell using "fittextflow={firstlinedist=capheight}". * "fitmethod=auto" scales the text until it entirely fits into * the cell. (You can use the "minfontsize" option to define a * lower limit when scaling the text, if required.) * Note that if "fitmethod=auto" is not used the row height will * be increased until the text fits completely into the cell. * "verticalalign=top" will place the text at the top of the * cell. * "rowheight" defines the row height. * "margin" adds some empty space between the text and the cell * borders. */ tfcell_opts = "textflow=" + tf + " fittextflow={firstlinedist=capheight verticalalign=top" + " fitmethod=auto}" + " rowheight=" + rwother + " margin=" + margin; /* Add the table cell */ tbl = p.add_table_cell(tbl, col + j, row + i, "", tfcell_opts); if (tbl == -1) throw new Exception("Error: " + p.get_errmsg()); } } /* ------------------------------------ * Place the table on one or more pages * ------------------------------------ */ /* Prepare the option list for fitting the table. * "header=1" will repeat the first row at the beginning of each new * page. The "stroke" option will stroke lines with two different line * widths. The table frame as well as each vertical line to the right of * a day-of-the-week cell is stroked with a line width of 1, all other * lines are stroked with a line width of 0.3. */ fittab_opts = "header=1 stroke={" + "{line=frame linewidth=1} {line=other linewidth=0.3} " + "{line=vert2 linewidth=1}}"; /* Loop until all of the table is placed; create new pages as long as * more table instances need to be placed */ do { /* Place the table instance */ result = p.fit_table(tbl, llx, lly, urx, ury, fittab_opts); if (result.equals("_error")) throw new Exception ("Couldn't place table: " + p.get_errmsg()); /* A return value of "break" has been explicitly specified in * add_table_cell() when adding the cell for a certain time interval * after which a new page shall be started. */ if (result.equals("_boxfull") || result.equals("break")) { p.setfont(regularfont, fontsize); p.fit_textline("-- Continued --", urx, ycontinued, "position {right top}"); p.end_page_ext(""); p.begin_page_ext(pagewidth, pageheight, ""); } } while (result.equals("_boxfull") || result.equals("break")); p.end_page_ext(""); p.end_document(""); } catch (PDFlibException e) { System.err.println("PDFlib exception occurred:"); System.err.println("[" + e.get_errnum() + "] " + e.get_apiname() + ": " + e.get_errmsg()); exitcode = 1; } catch (Exception e) { System.err.println(e.toString()); exitcode = 1; } finally { if (p != null) { p.delete(); } System.exit(exitcode); } } }