PDFlib Cookbook

cookbook

table/table_schedule

Create a weekly booking plan for the meeting rooms of a company.

Download Java Code  Switch to PHP Code  Show Output 

/*
 * 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("NotoSerif-Bold", "unicode", "");
            if (boldfont == -1)
                throw new Exception("Error: " + p.get_errmsg());
            
            regularfont = p.load_font("NotoSerif-Regular", "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);
        }
    }
}