org.unitime.timetable.webutil.pdf.PdfEventTableBuilder.java Source code

Java tutorial

Introduction

Here is the source code for org.unitime.timetable.webutil.pdf.PdfEventTableBuilder.java

Source

/*
 * UniTime 3.2 (University Timetabling Application)
 * Copyright (C) 2008 - 2010, UniTime LLC, and individual contributors
 * as indicated by the @authors tag.
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License along
 * with this program.  If not, see <http://www.gnu.org/licenses/>.
 * 
*/
package org.unitime.timetable.webutil.pdf;

import java.awt.Color;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.TreeSet;

import javax.servlet.jsp.JspWriter;

import org.unitime.commons.Debug;
import org.unitime.commons.web.htmlgen.TableStream;
import org.unitime.timetable.ApplicationProperties;
import org.unitime.timetable.form.EventListForm;
import org.unitime.timetable.form.MeetingListForm;
import org.unitime.timetable.model.ClassEvent;
import org.unitime.timetable.model.CourseEvent;
import org.unitime.timetable.model.Event;
import org.unitime.timetable.model.ExamEvent;
import org.unitime.timetable.model.Meeting;
import org.unitime.timetable.model.RelatedCourseInfo;
import org.unitime.timetable.model.Event.MultiMeeting;
import org.unitime.timetable.model.dao.ClassEventDAO;
import org.unitime.timetable.model.dao.CourseEventDAO;
import org.unitime.timetable.model.dao.ExamEventDAO;
import org.unitime.timetable.util.Constants;
import org.unitime.timetable.util.PdfEventHandler;
import org.unitime.timetable.util.PdfFont;
import org.unitime.timetable.webutil.WebEventTableBuilder;

import com.lowagie.text.Chunk;
import com.lowagie.text.Document;
import com.lowagie.text.Element;
import com.lowagie.text.PageSize;
import com.lowagie.text.Paragraph;
import com.lowagie.text.pdf.PdfPCell;
import com.lowagie.text.pdf.PdfPTable;
import com.lowagie.text.pdf.PdfWriter;

public class PdfEventTableBuilder extends WebEventTableBuilder {
    protected PdfWriter iWriter = null;
    protected Document iDocument = null;
    protected PdfPTable iPdfTable = null;

    protected Color iBgColor = Color.WHITE;
    protected boolean iUnderline = false;
    protected boolean iOverline = false;

    protected Color iTextColor = Color.BLACK;
    protected boolean iTextItalic = false;

    public PdfEventTableBuilder() {
        super();
    }

    public int getMaxResults() {
        return 1500;
    }

    public PdfPCell createCell() {
        PdfPCell cell = new PdfPCell();
        cell.setBorderColor(Color.BLACK);
        cell.setPadding(3);
        cell.setBorderWidth(0);
        cell.setVerticalAlignment(Element.ALIGN_TOP);
        cell.setHorizontalAlignment(Element.ALIGN_CENTER);
        cell.setBackgroundColor(iBgColor);
        if (iUnderline)
            cell.setBorderWidthBottom(1);
        if (iOverline)
            cell.setBorderWidthTop(0.5f);
        return cell;
    }

    public void addText(PdfPCell cell, String text) {
        addText(cell, text, false, iTextItalic, Element.ALIGN_LEFT, iTextColor, true);
    }

    public void addText(PdfPCell cell, String text, boolean bold, int orientation) {
        addText(cell, text, bold, iTextItalic, orientation, iTextColor, true);
    }

    public void addText(PdfPCell cell, String text, int orientation) {
        addText(cell, text, false, iTextItalic, orientation, iTextColor, true);
    }

    public void addText(PdfPCell cell, String text, boolean bold, boolean italic, int orientation, Color color,
            boolean newLine) {
        if (text == null)
            return;
        if (cell.getPhrase() == null) {
            Chunk ch = new Chunk(text, PdfFont.getSmallFont(bold, italic, color));
            cell.setPhrase(new Paragraph(ch));
            cell.setVerticalAlignment(Element.ALIGN_TOP);
            cell.setHorizontalAlignment(orientation);
        } else {
            cell.getPhrase()
                    .add(new Chunk((newLine ? "\n" : "") + text, PdfFont.getSmallFont(bold, italic, color)));
        }
    }

    public float[] getWidths(boolean events, boolean mainContact) {
        if (events) {
            if (mainContact)
                return new float[] { 200, 90, 80, 100, 100, 120 };
            else
                return new float[] { 200, 90, 80, 100, 100 };
        } else {
            if (mainContact)
                return new float[] { 150, 85, 50, 50, 100, 110, 90, 80, 120, 75 };
            return new float[] { 200, 85, 75, 50, 150, 100, 100, 100 };
        }
    }

    protected void pdfBuildTableHeader(boolean events, boolean mainContact, int numEventsOrMeetings) {
        if (events) {
            PdfPCell c;
            if (numEventsOrMeetings > getMaxResults()) {
                c = createCell();
                addText(c,
                        "**Warning: More than " + getMaxResults()
                                + " events match your search criteria. Only the first " + getMaxResults()
                                + " events are displayed. Please, redefine the search criteria in your filter.",
                        true, Element.ALIGN_LEFT);
                c.setColspan(mainContact ? 6 : 5);
                iPdfTable.addCell(c);
            }
            iBgColor = new Color(224, 224, 224);
            //first line
            c = createCell();
            addText(c, LABEL, true, Element.ALIGN_LEFT);
            iPdfTable.addCell(c);
            c = createCell();
            addText(c, ENROLLMENT, true, Element.ALIGN_RIGHT);
            iPdfTable.addCell(c);
            c = createCell();
            addText(c, EVENT_CAPACITY, true, Element.ALIGN_RIGHT);
            iPdfTable.addCell(c);
            c = createCell();
            addText(c, SPONSORING_ORG, true, Element.ALIGN_LEFT);
            iPdfTable.addCell(c);
            c = createCell();
            addText(c, EVENT_TYPE, true, Element.ALIGN_LEFT);
            iPdfTable.addCell(c);
            if (mainContact) {
                c = createCell();
                addText(c, MAIN_CONTACT, true, Element.ALIGN_LEFT);
                iPdfTable.addCell(c);
            }
            //second line
            iBgColor = new Color(244, 244, 244);
            iUnderline = true;
            c = createCell();
            iPdfTable.addCell(c);
            c = createCell();
            c.setColspan(2);
            addText(c, MEETING_DATE, true, Element.ALIGN_LEFT);
            iPdfTable.addCell(c);
            c = createCell();
            addText(c, MEETING_TIME, true, Element.ALIGN_LEFT);
            iPdfTable.addCell(c);
            c = createCell();
            addText(c, MEETING_LOCATION, true, Element.ALIGN_LEFT);
            iPdfTable.addCell(c);
            if (mainContact) {
                c = createCell();
                addText(c, APPROVED_DATE, true, Element.ALIGN_LEFT);
                iPdfTable.addCell(c);
            }
            if (numEventsOrMeetings <= getMaxResults()) {
                iPdfTable.setHeaderRows(2);
            } else {
                iPdfTable.setHeaderRows(3);
            }
        } else {
            PdfPCell c;
            if (numEventsOrMeetings > getMaxResults()) {
                c = createCell();
                addText(c,
                        "**Warning: More than " + getMaxResults()
                                + " meetings match your search criteria. Only the first " + getMaxResults()
                                + " meetings are displayed. Please, redefine the search criteria in your filter.",
                        true, Element.ALIGN_LEFT);
                c.setColspan(mainContact ? 10 : 9);
                iPdfTable.addCell(c);
            }
            iBgColor = new Color(224, 224, 224);
            //first line
            iUnderline = true;
            c = createCell();
            addText(c, LABEL, true, Element.ALIGN_LEFT);
            iPdfTable.addCell(c);
            c = createCell();
            addText(c, EVENT_TYPE, true, Element.ALIGN_LEFT);
            iPdfTable.addCell(c);
            c = createCell();
            addText(c, (mainContact ? "Enrl." : ENROLLMENT), true, Element.ALIGN_RIGHT);
            iPdfTable.addCell(c);
            c = createCell();
            addText(c, (mainContact ? "Cap." : EVENT_CAPACITY), true, Element.ALIGN_RIGHT);
            iPdfTable.addCell(c);
            c = createCell();
            addText(c, SPONSORING_ORG, true, Element.ALIGN_LEFT);
            iPdfTable.addCell(c);
            c = createCell();
            addText(c, MEETING_DATE, true, Element.ALIGN_LEFT);
            iPdfTable.addCell(c);
            c = createCell();
            addText(c, MEETING_TIME, true, Element.ALIGN_LEFT);
            iPdfTable.addCell(c);
            c = createCell();
            addText(c, MEETING_LOCATION, true, Element.ALIGN_LEFT);
            iPdfTable.addCell(c);
            if (mainContact) {
                c = createCell();
                addText(c, MAIN_CONTACT, true, Element.ALIGN_LEFT);
                iPdfTable.addCell(c);
                c = createCell();
                addText(c, APPROVED_DATE, true, Element.ALIGN_LEFT);
                iPdfTable.addCell(c);
            }
            if (numEventsOrMeetings <= getMaxResults()) {
                iPdfTable.setHeaderRows(1);
            } else {
                iPdfTable.setHeaderRows(2);
            }

        }
        iBgColor = Color.WHITE;
        iUnderline = false;
    }

    private PdfPCell pdfBuildEventName(Event e) {
        PdfPCell cell = createCell();
        addText(cell, e.getEventName() == null ? "" : e.getEventName(), true, Element.ALIGN_LEFT);
        return cell;
    }

    private PdfPCell pdfBuildEventCapacity(Event e) {
        PdfPCell cell = createCell();
        int minCap = (e.getMinCapacity() == null ? -1 : e.getMinCapacity());
        int maxCap = (e.getMaxCapacity() == null ? -1 : e.getMaxCapacity());
        if (minCap == -1) {

        } else {
            if (maxCap != -1) {
                if (maxCap != minCap) {
                    addText(cell, minCap + "-" + maxCap, Element.ALIGN_RIGHT);
                } else {
                    addText(cell, String.valueOf(minCap), Element.ALIGN_RIGHT);
                }
            }
        }
        return cell;
    }

    private PdfPCell pdfBuildEventEnrollment(Event e) {
        PdfPCell cell = createCell();
        if (Event.sEventTypeClass == e.getEventType()) {
            ClassEvent ce = new ClassEventDAO().get(Long.valueOf(e.getUniqueId()));
            if (ce.getClazz().getEnrollment() != null) {
                addText(cell, ce.getClazz().getEnrollment().toString(), Element.ALIGN_RIGHT);
            } else {
                addText(cell, "0", Element.ALIGN_RIGHT);
            }
        } else if (Event.sEventTypeFinalExam == e.getEventType()
                || Event.sEventTypeMidtermExam == e.getEventType()) {
            ExamEvent ee = new ExamEventDAO().get(e.getUniqueId());
            addText(cell, String.valueOf(ee.getExam().countStudents()), Element.ALIGN_RIGHT);
        } else if (Event.sEventTypeCourse == e.getEventType()) {
            CourseEvent ce = new CourseEventDAO().get(e.getUniqueId());
            int enrl = 0;
            for (RelatedCourseInfo rci : ce.getRelatedCourses())
                enrl += rci.countStudents();
            addText(cell, String.valueOf(enrl), Element.ALIGN_RIGHT);
        }
        return (cell);
    }

    private PdfPCell pdfBuildSponsoringOrg(Event e) {
        PdfPCell cell = createCell();
        addText(cell, e.getSponsoringOrganization() == null ? "" : e.getSponsoringOrganization().getName());
        return cell;
    }

    private PdfPCell pdfBuildEventTypeAbbv(Event e) {
        PdfPCell cell = createCell();
        addText(cell, e.getEventTypeAbbv());
        return cell;
    }

    private PdfPCell pdfBuildMainContactName(Event e) {
        PdfPCell cell = createCell();
        if (e.getMainContact() != null)
            addText(cell,
                    (e.getMainContact().getLastName() == null ? "" : (e.getMainContact().getLastName() + ", "))
                            + (e.getMainContact().getFirstName() == null ? "" : e.getMainContact().getFirstName()));
        return cell;
    }

    private PdfPCell pdfBuildEmptyMeetingInfo() {
        PdfPCell cell = createCell();
        return cell;
    }

    private PdfPCell pdfBuildDate(Meeting m) {
        PdfPCell cell = createCell();
        addText(cell, sDateFormat.format(m.getMeetingDate()));
        return cell;
    }

    private PdfPCell pdfBuildDate(MultiMeeting m) {
        PdfPCell cell = createCell();
        Calendar c = Calendar.getInstance();
        c.setTime(m.getMeetings().first().getMeetingDate());
        int y1 = c.get(Calendar.YEAR);
        c.setTime(m.getMeetings().last().getMeetingDate());
        int y2 = c.get(Calendar.YEAR);
        addText(cell,
                m.getDays() + " "
                        + (y1 == y2 ? sDateFormatM1 : sDateFormatM2)
                                .format(m.getMeetings().first().getMeetingDate())
                        + " - " + sDateFormatM2.format(m.getMeetings().last().getMeetingDate()));
        return cell;
    }

    private PdfPCell pdfBuildTime(Meeting m) {
        PdfPCell cell = createCell();
        addText(cell, m.isAllDay() ? "All Day"
                : Constants
                        .toTime(Constants.SLOT_LENGTH_MIN * m.getStartPeriod() + Constants.FIRST_SLOT_TIME_MIN
                                + (m.getStartOffset() == null ? 0 : m.getStartOffset()))
                        + " - "
                        + Constants.toTime(
                                Constants.SLOT_LENGTH_MIN * m.getStopPeriod() + Constants.FIRST_SLOT_TIME_MIN
                                        + (m.getStopOffset() == null ? 0 : m.getStopOffset())));
        return cell;
    }

    private PdfPCell pdfBuildLocation(Meeting m) {
        PdfPCell cell = createCell();
        addText(cell, m.getLocation() == null ? "" : m.getLocation().getLabel());
        return cell;
    }

    private PdfPCell pdfBuildApproved(Meeting m) {
        PdfPCell cell = createCell();
        SimpleDateFormat df = new SimpleDateFormat("MM/dd/yy", Locale.US);
        addText(cell, m.getApprovedDate() == null ? "" : df.format(m.getApprovedDate()));
        return cell;
    }

    private PdfPCell pdfBuildApproved(MultiMeeting mm) {
        PdfPCell cell = createCell();
        SimpleDateFormat df = new SimpleDateFormat("MM/dd/yy", Locale.US);
        Date approvalDate = null; //latest approval date
        for (Meeting m : mm.getMeetings())
            if (approvalDate == null || approvalDate.compareTo(m.getApprovedDate()) < 0)
                approvalDate = m.getApprovedDate();
        addText(cell, approvalDate == null ? "" : df.format(approvalDate));
        return cell;
    }

    private void pdfAddEventsRowsToTable(Event e, boolean mainContact, TreeSet<MultiMeeting> meetings) {
        boolean allPast = true;
        for (MultiMeeting meeting : meetings) {
            if (!meeting.isPast()) {
                allPast = false;
                break;
            }
        }
        if (allPast) {
            iTextColor = Color.GRAY;
            iTextItalic = true;
        }
        iBgColor = new Color(223, 231, 242);
        iPdfTable.addCell(pdfBuildEventName(e));
        iPdfTable.addCell(pdfBuildEventEnrollment(e));
        iPdfTable.addCell(pdfBuildEventCapacity(e));
        iPdfTable.addCell(pdfBuildSponsoringOrg(e));
        iPdfTable.addCell(pdfBuildEventTypeAbbv(e));
        if (mainContact)
            iPdfTable.addCell(pdfBuildMainContactName(e));
        iTextColor = Color.BLACK;
        iTextItalic = false;
        iBgColor = Color.WHITE;
    }

    private void pdfAddMeetingRowsToTable(MultiMeeting mm, boolean mainContact, boolean printOverlaps) {
        Meeting m = mm.getMeetings().first();
        if (mm.isPast()) {
            iTextColor = Color.GRAY;
            iTextItalic = true;
        } else {
            if (m.isApproved()) {
                //bgColor = "#DDFFDD";
            } else {
                iBgColor = new Color(255, 255, 221);
            }
        }
        iPdfTable.addCell(pdfBuildEmptyMeetingInfo());
        PdfPCell cell = mm.getMeetings().size() == 1 ? pdfBuildDate(m) : pdfBuildDate(mm);
        cell.setColspan(2);
        iPdfTable.addCell(cell);
        iPdfTable.addCell(pdfBuildTime(m));
        iPdfTable.addCell(pdfBuildLocation(m));
        if (mainContact)
            iPdfTable.addCell(mm.getMeetings().size() == 1 ? pdfBuildApproved(m) : pdfBuildApproved(mm));
        iTextColor = Color.BLACK;
        iTextItalic = false;
        iBgColor = Color.WHITE;
        if (printOverlaps) {
            TreeSet<Meeting> overlaps = new TreeSet();
            for (Meeting mx : mm.getMeetings()) {
                overlaps.addAll(mx.getTimeRoomOverlaps());
            }
            if (!overlaps.isEmpty()) {
                for (MultiMeeting o : Event.getMultiMeetings(overlaps))
                    pdfAddOverlappingMeetingToTable(o, mainContact);
            }
        }
    }

    private void pdfAddOverlappingMeetingToTable(MultiMeeting mm, boolean mainContact) {
        Meeting m = mm.getMeetings().first();
        if (mm.isPast()) {
            iTextColor = Color.GRAY;
            iTextItalic = true;
        }
        iBgColor = new Color(255, 215, 215);
        PdfPCell cell = createCell();
        addText(cell, "   Conf/w " + m.getEvent().getEventName() + " (" + m.getEvent().getEventTypeAbbv() + ")");
        iPdfTable.addCell(cell);
        cell = (mm.getMeetings().size() == 1 ? pdfBuildDate(m) : pdfBuildDate(mm));
        cell.setColspan(2);
        iPdfTable.addCell(cell);
        iPdfTable.addCell(pdfBuildTime(m));
        iPdfTable.addCell(pdfBuildLocation(m));
        if (mainContact)
            iPdfTable.addCell(mm.getMeetings().size() == 1 ? pdfBuildApproved(m) : pdfBuildApproved(mm));
        iTextColor = Color.BLACK;
        iTextItalic = false;
        iBgColor = Color.WHITE;
    }

    private void pdfAddMeetingRowsToTable(Meeting m, boolean mainContact, Event lastEvent, Date now, boolean line,
            boolean printOverlaps) {
        if (m.getStartTime().before(now)) {
            iTextColor = Color.GRAY;
            iTextItalic = true;
        } else {
            if (m.isApproved()) {
                //bgColor = "#DDFFDD";
            } else {
                iBgColor = new Color(255, 255, 221);
            }
        }
        if (line && lastEvent != null && !lastEvent.getUniqueId().equals(m.getEvent().getUniqueId())) {
            iOverline = true;
        }
        if (lastEvent != null && lastEvent.getUniqueId().equals(m.getEvent().getUniqueId())) {
            PdfPCell cell = createCell();
            iPdfTable.addCell(cell);
            iPdfTable.addCell(cell);
            iPdfTable.addCell(cell);
            iPdfTable.addCell(cell);
            iPdfTable.addCell(cell);
        } else {
            iPdfTable.addCell(pdfBuildEventName(m.getEvent()));
            iPdfTable.addCell(pdfBuildEventTypeAbbv(m.getEvent()));
            iPdfTable.addCell(pdfBuildEventEnrollment(m.getEvent()));
            iPdfTable.addCell(pdfBuildEventCapacity(m.getEvent()));
            iPdfTable.addCell(pdfBuildSponsoringOrg(m.getEvent()));
        }
        iPdfTable.addCell(pdfBuildDate(m));
        iPdfTable.addCell(pdfBuildTime(m));
        iPdfTable.addCell(pdfBuildLocation(m));
        if (mainContact) {
            if (lastEvent != null && lastEvent.getUniqueId().equals(m.getEvent().getUniqueId())) {
                PdfPCell cell = createCell();
                iPdfTable.addCell(cell);
            } else {
                iPdfTable.addCell(pdfBuildMainContactName(m.getEvent()));
            }
            iPdfTable.addCell(pdfBuildApproved(m));
        }
        iTextColor = Color.BLACK;
        iTextItalic = false;
        iBgColor = Color.WHITE;
        iOverline = false;
        if (printOverlaps) {
            TreeSet<Meeting> overlaps = new TreeSet(m.getTimeRoomOverlaps());
            if (!overlaps.isEmpty()) {
                for (Meeting o : overlaps)
                    pdfAddOverlappingMeetingToTable(o, mainContact, now);
            }
        }
    }

    private void pdfAddOverlappingMeetingToTable(Meeting m, boolean mainContact, Date now) {
        if (m.getStartTime().before(now)) {
            iTextColor = Color.GRAY;
            iTextItalic = true;
        }
        iBgColor = new Color(255, 215, 215);
        PdfPCell cell = createCell();
        addText(cell, "   Conf/w " + (m.getEvent().getEventName() == null ? "" : m.getEvent().getEventName()) + " ("
                + m.getEvent().getEventTypeAbbv() + ")");
        cell.setColspan(2);
        iPdfTable.addCell(cell);
        iPdfTable.addCell(pdfBuildEventEnrollment(m.getEvent()));
        iPdfTable.addCell(pdfBuildEventCapacity(m.getEvent()));
        iPdfTable.addCell(pdfBuildSponsoringOrg(m.getEvent()));
        iPdfTable.addCell(pdfBuildDate(m));
        iPdfTable.addCell(pdfBuildTime(m));
        iPdfTable.addCell(pdfBuildLocation(m));
        if (mainContact) {
            iPdfTable.addCell(pdfBuildMainContactName(m.getEvent()));
            iPdfTable.addCell(pdfBuildApproved(m));
        }
        iTextColor = Color.BLACK;
        iTextItalic = false;
        iBgColor = Color.WHITE;
    }

    public File pdfTableForEvents(EventListForm form) {
        List events = loadEvents(form);
        if (events.isEmpty())
            return null;

        boolean mainContact = form.isAdmin() || form.isEventManager();

        FileOutputStream out = null;
        try {
            File file = ApplicationProperties.getTempFile("events", "pdf");

            iDocument = new Document(PageSize.LETTER, 15, 15, 15, 30);

            out = new FileOutputStream(file);
            iWriter = PdfEventHandler.initFooter(iDocument, out);
            iDocument.open();

            iPdfTable = new PdfPTable(getWidths(true, mainContact));
            iPdfTable.setWidthPercentage(100);
            iPdfTable.getDefaultCell().setPadding(3);
            iPdfTable.getDefaultCell().setBorderWidth(0);
            iPdfTable.setSplitRows(false);

            pdfBuildTableHeader(true, mainContact, events.size());

            for (Iterator it = events.iterator(); it.hasNext();) {
                Event event = (Event) it.next();
                if (form.getMode() == EventListForm.sModeEvents4Approval) {
                    boolean myApproval = false;
                    for (Iterator j = event.getMeetings().iterator(); j.hasNext();) {
                        Meeting m = (Meeting) j.next();
                        if (m.getApprovedDate() == null && m.getLocation() != null && form.getManagingDepartments()
                                .contains(m.getLocation().getControllingDepartment())) {
                            myApproval = true;
                            break;
                        }
                    }
                    if (!myApproval)
                        continue;
                }
                TreeSet<MultiMeeting> meetings = event.getMultiMeetings();
                pdfAddEventsRowsToTable(event, mainContact, meetings);
                for (MultiMeeting meeting : meetings)
                    pdfAddMeetingRowsToTable(meeting, mainContact, form.getDispConflicts());
            }

            iDocument.add(iPdfTable);
            iDocument.close();

            return file;
        } catch (Exception e) {
            Debug.error(e);
        } finally {
            try {
                if (out != null)
                    out.close();
            } catch (IOException e) {
            }
        }
        return null;
    }

    public File pdfTableForMeetings(MeetingListForm form) {
        List meetings = loadMeetings(form);

        if (meetings.isEmpty())
            return null;

        boolean mainContact = form.isAdmin() || form.isEventManager();

        FileOutputStream out = null;
        try {
            File file = ApplicationProperties.getTempFile("meetings", "pdf");

            float[] widths = getWidths(false, mainContact);

            iDocument = new Document(PageSize.LETTER.rotate(), 15, 15, 15, 30);

            out = new FileOutputStream(file);
            iWriter = PdfEventHandler.initFooter(iDocument, out);
            iDocument.open();

            iPdfTable = new PdfPTable(widths);
            iPdfTable.setWidthPercentage(100);
            iPdfTable.getDefaultCell().setPadding(3);
            iPdfTable.getDefaultCell().setBorderWidth(0);
            iPdfTable.setSplitRows(false);

            pdfBuildTableHeader(false, mainContact, meetings.size());

            Event lastEvent = null;
            Date now = new Date();
            boolean line = MeetingListForm.sOrderByName.equals(form.getOrderBy());

            for (Iterator it = meetings.iterator(); it.hasNext();) {
                Meeting meeting = (Meeting) it.next();
                pdfAddMeetingRowsToTable(meeting, mainContact, lastEvent, now, line, form.getDispConflicts());
                lastEvent = meeting.getEvent();
            }

            iDocument.add(iPdfTable);
            iDocument.close();

            return file;
        } catch (Exception e) {
            Debug.error(e);
        } finally {
            try {
                if (out != null)
                    out.close();
            } catch (IOException e) {
            }
        }
        return null;
    }

    protected TableStream initTable(JspWriter outputStream) {
        TableStream table = new TableStream(outputStream);
        table.setWidth("100%");
        table.setBorder(0);
        table.setCellSpacing(0);
        table.setCellPadding(3);
        table.tableDefComplete();
        return (table);
    }

}