/* * Table schedule: * Create a weekly booking plan for the meeting rooms of a company * * For the weekly bookings of the meeting rooms in a company, create a table * with each cell representing a period of time on a day of the week for a * certain meeting room. If a meeting room is booked for a certain period of * time on a certain day of the week the corresponding cells will be colorized * and provided with some booking text. * Use the "colwidth" and "rowheight" options of add_table_cell() to create the * table as a kind of grid with unique and fixed column width and row height. * Use the "fitmethod=auto" option to decrease the font size if the booking text * is too large to fit completely into the cell. * Use the "matchbox" option of add_table_cell() to colorize cells. * * The table is to be spread over two pages with a defined row being the last * one on the first page. Use the "return" option of add_table_cell() to force * fit_table() to a break after having placed the last row containing the cell. * * Required software: PDFlib/PDFlib+PDI/PPS 9 * Required data: none */ package com.pdflib.cookbook.pdflib.table; import java.math.BigDecimal; import java.math.RoundingMode; import java.text.NumberFormat; import java.util.Locale; import com.pdflib.pdflib; import com.pdflib.PDFlibException; public class table_schedule { public static void main (String argv[]) { /* This is where the data files are. Adjust as necessary. */ String searchpath = "../input"; String outfile = "table_schedule.pdf"; String title = "Table Schedule"; pdflib p = null; int exitcode = 0; int row, col, tf=-1, tbl=-1; int i, j, t, 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 rowheight1 = 16, rowheight2 = 32; final String leading = "120%"; final int dayspan = 5, timespan=3, mroomspan = 2, croomspan=3; final double tstart = 5, tend = 22, tbreak = 12; /* The table coordinates are fixed */ final int llx = 50, urx = (int) pagewidth - llx; final int lly = 120, ury = (int) pageheight - lly; final int yoffset = 15; final int yheading = ury + 2 * yoffset; final int ycontinued = lly - yoffset; /* The widths of the first and the other columns is fixed */ final int cwfirst = 50, cwother = 30; final int maxdays = 6; final String days [] = { "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" }; final int maxrooms = 5; final String rooms [] = { "M1", "M2", "C1", "C2", "C3" }; final int idxDay = 0, idxStart = 1, idxEnd = 2, idxRoom = 3; final int idxText = 4, idxColor = 5; final int maxbookings = 6; final String bookings [] [] = { /* day, start, end, room, text, color */ {"1", "8", "12", "1", "Company Meeting", "rgb 0.8 0.36 0.36"}, {"2", "11", "20", "4", "Technical Workgroup", "rgb 1.0 0.84 0.0"}, {"4", "8", "16", "2", "QM Meeting", "rgb 0.0 0.8 0.82"}, {"5", "10", "12", "4", "Admin Training", "rgb 0.6 0.8 0.92"}, {"5", "14", "18", "4", "Admin Training", "rgb 0.6 0.8 0.92"}, {"6", "14", "22", "5", "Admin Training", "rgb 0.6 0.8 0.92"} }; 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("Booking Schedule", llx, yheading, ""); /* Prepare the general option list for adding a Textflow. * For an exact vertical alignment of Textflow and text lines note the * following: * The height of an uppercase letter is exactly represented by the * capheight value of the font. For this reason use the capheight in the * font size specification. For example, a capheight of 8.5 will * approximately result in a font size of 12 points. * "alignment=center" centers the text. * "leading" specifies the distance between to text lines. */ final String tf_opts = "font=" + regularfont + " alignment=center" + " fontsize={capheight=" + capheight + "} leading=" + leading; /* ------------------------------------------------------------------- * Add the Textflow cell containing the time heading which spans three * rows * ------------------------------------------------------------------- */ col = 1; row = 1; /* Add the Textflow to be placed in the heading cell */ tf = p.add_textflow(-1, "Time\nfrom\nto", 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}". * "colwidth" defines the width of the first column the cell is spanned. * "rowheight" defines the row height. * "margin" adds some empty space between the text and the cell borders. * "colspan" defines the number of columns the cell is spanned. */ tfcell_opts = "textflow=" + tf + " fittextflow={firstlinedist=capheight fitmethod=auto}" + " colwidth=" + cwfirst + " rowheight=" + rowheight1 + " margin=" + margin + " rowspan=" + timespan; tbl = p.add_table_cell(tbl, col, row, "", tfcell_opts); if (tbl == -1) throw new Exception("Error: " + p.get_errmsg()); /* ------------------------------------------------------------------- * Add the text line cells containing the days of the week headings in * the first row, spanning several columns each * ------------------------------------------------------------------- */ col = 2; row = 1; /* Prepare the option list: * "position={center top}" positions the text on the top left. * "fitmethod=auto" decreases the font size of the text if it is too * large to fit completely into the cell instead of increasing the row * height. * The height of an uppercase letter is exactly represented by the * capheight value of the font. For this reason use the capheight in the * font size specification. For example, to match a row height of 16, * you could use a capheight of 8.5 and a margin of 4. * "fitmethod=auto" will decrease the font size, if necessary, until the * text line fits completely into the cell. * "colwidth" defines the width of the first column the cell is spanned. * "rowheight" defines the row height. * "margin" adds some empty space between the text and the cell borders. * "colspan" defines the number of columns the cell is spanned. */ tlcell_opts = "fittextline={position={center top} fitmethod=auto" + " font=" + boldfont + " fontsize={capheight=" + capheight + "}} " + " colwidth=" + cwother + " rowheight=" + rowheight1 + " margin=" + margin + " colspan=" + dayspan; /* Add the table cells containing the days of the week */ for (i = 0; i < maxdays; i++) { tbl = p.add_table_cell(tbl, col, row, days[i], tlcell_opts); if (tbl == -1) throw new Exception("Error adding cell: " + p.get_errmsg()); col += dayspan; } /* -------------------------------------------------------------------- * In the second row below each day of the week, add the "Meeting Room" * and "Conference Room" Textflow heading cells. The two cells together * span the same number of columns as spanned by the day of the week. * -------------------------------------------------------------------- */ col = 2; row = 2; /* Loop over the number of days of the week */ for (i = 0; i < maxdays; i++) { /* Add the "Meeting Room" Textflow */ tf = p.add_textflow(-1, "Meeting Room", tf_opts); if (tf == -1) throw new Exception("Error: " + p.get_errmsg()); /* Add the "Meeting Room" Textflow cell */ tfcell_opts = "textflow=" + tf + " fittextflow={firstlinedist=capheight fitmethod=auto}" + " colwidth=" + cwother + " rowheight=" + rowheight2 + " margin=" + margin + " colspan=" + mroomspan; tbl = p.add_table_cell(tbl, col, row, "", tfcell_opts); if (tbl == -1) throw new Exception("Error: " + p.get_errmsg()); col += mroomspan; /* Add the "Conference Room" Textflow */ tf = p.add_textflow(-1, "Conference Room", tf_opts); if (tf == -1) throw new Exception("Error: " + p.get_errmsg()); /* Add the "Conference Room" Textflow cell */ tfcell_opts = "textflow=" + tf + " fittextflow={firstlinedist=capheight fitmethod=auto}" + " colwidth=" + cwother + " rowheight=" + rowheight2 + " margin=" + margin + " colspan=" + croomspan; tbl = p.add_table_cell(tbl, col, row, "", tfcell_opts); if (tbl == -1) throw new Exception("Error: " + p.get_errmsg()); col += croomspan; } /* --------------------------------------------------------------------- * In the third row below the "Meeting Room" and "Conference Room" cells * for each day of the week add five text line heading cells containing * the names of the meeting rooms. * --------------------------------------------------------------------- */ col = 2; row = 3; /* Prepare the option list for adding the cells */ tlcell_opts = "fittextline={position={center top} fitmethod=auto" + " font=" + regularfont + " fontsize={capheight=" + capheight + "}}"+ " colwidth=" + cwother + " rowheight=" + rowheight1 + " margin=" + margin; /* Loop over the number of days of the week */ for (i = 0; i < maxdays; i++) { /* Add the cells with the names of the room */ for (j = 0; j < maxrooms; j++) { tbl = p.add_table_cell(tbl, col++, row, rooms[j], tlcell_opts); if (tbl == -1) throw new Exception("Error adding cell: " + p.get_errmsg()); } } /* -------------------------------------------------------------- * In the first column add the Textflow cells containing the time * intervals, one cell for each hour * -------------------------------------------------------------- */ col = 1; row = 4; /* For outputting the time of the day, initialize the maximum number * of fraction digits to two */ NumberFormat form = NumberFormat.getInstance(Locale.US); form.setMaximumFractionDigits(2); form.setMinimumFractionDigits(2); /* Loop over all time intervals */ for (i = 1, t = (int) tstart; i <= tend - tstart; i++, t++) { /* Format the current time interval to a maximum of two fraction * digits */ BigDecimal value = new BigDecimal(t); BigDecimal roundedValue = value.setScale(2, RoundingMode.HALF_UP); String text = roundedValue.toString() + "\n"; value = new BigDecimal(t+1); roundedValue = value.setScale(2, RoundingMode.HALF_UP); text += roundedValue.toString(); /* Add the time interval Textflow */ tf = p.add_textflow(-1, text, tf_opts); if (tf == -1) throw new Exception("Error: " + p.get_errmsg()); /* Prepare the option list for adding the time interval headings */ tfcell_opts = "textflow=" + tf + " fittextflow={firstlinedist=capheight fitmethod=auto}" + " colwidth=" + cwfirst + " rowheight=" + rowheight2 + " 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 time * interval, e.g. of 12-13. 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 (t == tbreak) tfcell_opts += " return break"; /* Add the time interval Textflow cell */ tbl = p.add_table_cell(tbl, col, row++, "", tfcell_opts); if (tbl == -1) throw new Exception("Error adding cell: " + p.get_errmsg()); } /* ----------------------------------------------------------------- * For each booking item add a text line cell containing the booking * text and colorize it. Place the cell according to the day of the * week, time interval and meeting room affected. * ----------------------------------------------------------------- */ /* Loop over all bookings */ for (i = 0; i < maxbookings; i++) { /* Read the attributes of the current booking */ int start = Integer.valueOf(bookings[i][idxStart]).intValue(); int end = Integer.valueOf(bookings[i][idxEnd]).intValue(); int day = Integer.valueOf(bookings[i][idxDay]).intValue(); int room = Integer.valueOf(bookings[i][idxRoom]).intValue(); String text = bookings[i][idxText]; /* Get the column and row as well as the number of rows spanned by * the cell */ int rowspan = 1; col = 2 + ((day - 1) * dayspan) + (room - 1); row = 4 + (start - (int) tstart); if (end != start) rowspan = end - start; /* Prepare the option list for adding the booking item cell */ String opts = "fittextline={position={center} " + " fitmethod=auto font=" + regularfont + " orientate=west" + " fontsize={capheight=" + capheight + "}} " + " colwidth=" + cwother + " rowheight=" + rowheight2 + " margin=" + margin + " rowspan=" + rowspan + " matchbox={fillcolor={" + bookings[i][idxColor] + "}}"; tbl = p.add_table_cell(tbl, col, row, text, opts); if (tbl == -1) throw new Exception("Error adding cell: " + p.get_errmsg()); } /* ------------------------------------ * Place the table on one or more pages * ------------------------------------ */ /* Prepare the option list for fitting the table. * "header=3" will repeat the first three rows 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=3 stroke={" + "{line=frame linewidth=1} {line=other linewidth=0.3} "; for (i = 0; i < maxdays; i++) fittab_opts += "{line=vert" + (1+i*maxrooms) + " linewidth=1} "; fittab_opts += "}"; /* 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); } } }