package org.akaza.openclinica.view.form; import org.akaza.openclinica.bean.managestudy.StudyBean; import org.akaza.openclinica.bean.submit.DisplayItemBean; import org.akaza.openclinica.bean.submit.DisplayItemGroupBean; import org.akaza.openclinica.bean.submit.DisplaySectionBean; import org.akaza.openclinica.bean.submit.EventCRFBean; import org.akaza.openclinica.bean.submit.ItemDataBean; import org.akaza.openclinica.bean.submit.ItemFormMetadataBean; import org.akaza.openclinica.bean.submit.ResponseOptionBean; import org.akaza.openclinica.bean.submit.ResponseSetBean; import org.akaza.openclinica.bean.submit.SectionBean; import org.akaza.openclinica.control.managestudy.BeanFactory; import org.jdom.Document; import org.jdom.Element; import org.jdom.output.Format; import org.jdom.output.XMLOutputter; import java.io.IOException; import java.io.StringWriter; import java.io.Writer; import java.util.ArrayList; import java.util.List; import java.util.SortedMap; import java.util.TreeMap; /** * This class is used to generate the markup for a group-type printable table. * An array or List of DisplaySectionBeans is sequentially converted into XML to * create a Web page representing all of the sections of a CRF. If needed, the * code will reproduce rows that are saved in the database. The markup, a large * String generated from a JDOM Document object (HTML, basically) is then output * to a Web browser by a custom JSP tag. */ public class PrintHorizontalFormBuilder extends DefaultFormBuilder { private int maxColRow = 4; // The sections that make up the print version of the form private List<DisplaySectionBean> displaySectionBeans = new ArrayList<DisplaySectionBean>(); private StudyBean studyBean; private EventCRFBean eventCRFbean; // Does the HTTP request originate from a print data entry servlet? private boolean involvesDataEntry; // Have the form values already been saved during initial or double data // entry? private boolean hasDbFormValues; // Alter print view for Internet Explorer browsers private boolean isInternetExplorer=false; // Does the print view have to be reconfigured for IE browsers? private boolean reconfigureView; private SectionBean sectionBean; public PrintHorizontalFormBuilder() { } public List<DisplaySectionBean> getDisplaySectionBeans() { return displaySectionBeans; } public void setDisplaySectionBeans(List<DisplaySectionBean> displaySectionBeans) { this.displaySectionBeans = displaySectionBeans; } @Override public String createMarkup() { // If the CRF has // data associated with it, pass on the responsibility to another object ViewPersistanceHandler persistanceHandler = new ViewPersistanceHandler(); ViewBuilderPrintDecorator builderUtil = new ViewBuilderPrintDecorator(); // This object holds the printed output of the JDom Document object, // which represents // the XML for each section's HTML tables. The object is re-written // each time a new section is generated Writer writer = new StringWriter(); // This object contains all of the markup for all of the sections. StringBuilder webPageBuilder = new StringBuilder(); // Keep track of the section number so we can create page numbers int pageNumber = 0; if (isInternetExplorer) { for (DisplaySectionBean displaySecBean : this.displaySectionBeans) { this.reconfigureView = builderUtil.hasThreePlusColumns(displaySecBean); // Now the application knows that the view for at least one // section has to be // reformulated for IE if (reconfigureView) break; } } int uniqueId = 0; // Print all the sections of a group-type table for (DisplaySectionBean displaySecBean : this.displaySectionBeans) { // The CellFactoryPrintDecorator object that generates the content // for HTML table TD cells. CellFactoryPrintDecorator cellFactory = new CellFactoryPrintDecorator(); // The object that handles the repetition model attributes for the // HTML table elements RepeatManager repeatManager = new RepeatManager(); // These classes "decorate" the FormBeanUtil and ViewBuilderUtil // classes to // provide special services required in printing FormBeanUtilDecorator formUtilDecorator = new FormBeanUtilDecorator(); // Does this particular section have to be reconfigured for printing // in IE browsers? boolean changeHTMLForIE = false; if (reconfigureView) { // changeHTMLForIE = builderUtil.hasThreePlusColumns(displaySecBean); } // We have to change the Section's ItemGroupBeans if the Section has // group tables exceeding three columns, in terms of printing for IE // browsers. // Any ItemGroupBean specifically has to be reduced to one column, // if it exceeds // three columns; changeHTMLForIE is 'true' if this section has any // group tables // that are 3+ columns // if (changeHTMLForIE) { // List<DisplayItemGroupBean> newGroupBeans = builderUtil.reduceColumnsGroupTables(displaySecBean.getDisplayFormGroups()); // // // Now set the display section beans groups to the reshuffled // // list // displaySecBean.setDisplayFormGroups(newGroupBeans); // } // increment the page number ++pageNumber; // The SectionBean associated with this section sectionBean = displaySecBean.getSection(); if (involvesDataEntry) { List<ItemDataBean> itemDataBeans; persistanceHandler = new ViewPersistanceHandler(); itemDataBeans = persistanceHandler.fetchPersistedData(sectionBean.getId(), eventCRFbean.getId()); if (!itemDataBeans.isEmpty()) { hasDbFormValues = true; } persistanceHandler.setItemDataBeans(itemDataBeans); } // Keep track of whether a group has any repeat behavior; true or // false boolean repeatFlag; // The number of repeating table rows that the group will start // with. int repeatNumber; // the div tag that will be the root node for each printable section Element divRoot = new Element("div"); divRoot.setAttribute("id", ("toplevel" + pageNumber)); divRoot.setAttribute("class", "toplevel"); // remove float properties for IE browsers if (isInternetExplorer) { divRoot.setAttribute("style", "float:none"); } Document doc = new Document(divRoot); // Show the section's title, subtitle, or instructions builderUtil.showTitles(divRoot, sectionBean, pageNumber, isInternetExplorer); // One way to generate an id for the repeating tbody or tr element // The tabindex attribute for select and input tags int tabindex = 1; // Should discrepancy note icons be displayed boolean hasDiscrepancyMgt = false; StudyBean studBean = this.getStudyBean(); if (studBean != null && studBean.getStudyParameterConfig().getDiscrepancyManagement().equalsIgnoreCase("true")) { hasDiscrepancyMgt = true; } // Create a table for every DisplayItemGroupBean // A DisplayItemGroupBean contains an ItemGroupBean and // its list of DisplayItemBeans for (DisplayItemGroupBean displayItemGroup : displaySecBean.getDisplayFormGroups()) { ArrayList headerlist = new ArrayList(); ArrayList bodylist = new ArrayList(); ArrayList subHeadList = new ArrayList(); List<DisplayItemBean> currentDisplayItems = displayItemGroup.getItems(); // A Map that contains persistent (stored in a database), // repeated rows // in a matrix type table // The Map index is the Item id of the first member of the row; // the value is a List // of item beans that make up the row SortedMap<Integer, List<ItemDataBean>> ordinalItemDataMap = new TreeMap<Integer, List<ItemDataBean>>(); // Is this a persistent matrix table and does it already have // repeated rows // in the database? boolean hasStoredRepeatedRows = false; // Is this a non-group type table that shares the same section // as a group table? boolean unGroupedTable = displayItemGroup.getItemGroupBean().getName().equalsIgnoreCase(BeanFactory.UNGROUPED); // Load any database values into the DisplayItemBeans if (hasDbFormValues) { currentDisplayItems = persistanceHandler.loadDataIntoDisplayBeans(currentDisplayItems, (!unGroupedTable)); /* * The highest number ordinal represents how many repeated * rows there are. If the ordinal in ItemDataBeans > 1, then * we know that the group has persistent repeated rows. Get * a structure that maps each ordinal (i.e., >= 2) to its * corresponding List of ItemDataBeans. Then iterate the * existing DisplayBeans, with the number of new rows * equaling the highest ordinal number minus 1 (meaning, the * first row represents the row of the group table that * would exist if the user displayed the table, but didn't * generate any new rows). For example, in a List of * ItemDataBeans, if the highest ordinal property among * these beans is 5, then the matrix table has 4 repeated * rows from the database. Provide each new row with its * values by using the ItemDataBeans. */ if (involvesDataEntry && !unGroupedTable && persistanceHandler.hasPersistentRepeatedRows(currentDisplayItems)) { hasStoredRepeatedRows = true; // if the displayitems contain duplicate item ids, then // these duplicates // represent repeated rows. Separate them into a Map of // new rows that // will be appended to the HTML table. ordinalItemDataMap = persistanceHandler.handleExtraGroupRows(); } }// end if hasDbFormValues // Does the table have a group header? String groupHeader = displayItemGroup.getGroupMetaBean().getHeader(); boolean hasGroupHeader = groupHeader != null && groupHeader.length() > 0; // Add group header, if there is one if (hasGroupHeader) { Element divGroupHeader = new Element("div"); // necessary? divGroupHeader.setAttribute("class", "aka_group_header"); Element strong = new Element("strong"); strong.setAttribute("style", "float:none"); strong.addContent(groupHeader); divGroupHeader.addContent(strong); divRoot.addContent(divGroupHeader); } Element tableDiv = new Element("div"); tableDiv.setAttribute("class", "tableDiv"); if (isInternetExplorer) { tableDiv.setAttribute("style", "float:none"); } divRoot.addContent(tableDiv); // This group represents "orphaned" items (those without a // group) if // the FormGroupBean has a group label of UNGROUPED Element orphanTable = null; if (unGroupedTable) { orphanTable = formUtilDecorator.createXHTMLTableFromNonGroup(currentDisplayItems, tabindex, hasDiscrepancyMgt, hasDbFormValues, true); // We have to track the point the tabindex has reached here // The tabindex will increment by the size of the // displayItemGroup List tabindex += currentDisplayItems.size(); tableDiv.addContent(orphanTable); continue; }// end if unGroupedTable uniqueId++; String repeatParentId = "repeatParent" + uniqueId; repeatNumber = displayItemGroup.getGroupMetaBean().getRepeatNum(); // If the form has repeat behavior, this number is > 0 // Do not allow repeat numbers < 1 repeatNumber = repeatNumber < 1 ? 1 : repeatNumber; // And a limit of 12 repeatNumber = repeatNumber > 12 ? 12 : repeatNumber; // This is always true during this iteration repeatFlag = true; Element table = createTable(); // add the thead element Element thead = new Element("tr"); tableDiv.addContent(table); // table.addContent(thead); // Does this group involve a Horizontal checkbox or radio // button? boolean hasResponseLayout = builderUtil.hasResponseLayout(currentDisplayItems); // add th elements to the thead element // We have to create an extra thead column for the Remove Row // button, if // the table involves repeating rows; thus the final boolean // parameter List<Element> thTags = repeatFlag ? createTheadContentsFromDisplayItems(currentDisplayItems, true) : createTheadContentsFromDisplayItems(currentDisplayItems, false); int i = 0; for (Element el : thTags) { i++; thead.addContent(el); if(i%maxColRow == 0) { headerlist.add(thead); thead = new Element("tr"); } } if(i%maxColRow!=0)headerlist.add(thead); // Make sure the layout for "horizontal" checkboxes or radios is // displayed // in this manner. if (hasResponseLayout) { addResponseLayoutRow(subHeadList, currentDisplayItems); } Element row; Element td; // For each row in the table row = new Element("tr"); // If the group has repeat behavior and repeats row by row, // then the // repetition model type attributes have to be added to the tr // tag if (repeatFlag && !(involvesDataEntry && hasStoredRepeatedRows)) { table = repeatManager.addParentRepeatAttributes(table, repeatParentId, repeatNumber, displayItemGroup.getGroupMetaBean().getRepeatMax()); } // The content for the table cells. For each item... int j = 0; for (DisplayItemBean displayBean : currentDisplayItems) { j++; // What type of input: text, radio, checkbox, etc.? String responseName = displayBean.getMetadata().getResponseSet().getResponseType().getName(); // We have to create cells in a different way if the input // is radio or checkbox, and the response_layout is // horizontal if (displayBean.getMetadata().getResponseLayout().equalsIgnoreCase("horizontal") && (responseName.equalsIgnoreCase("checkbox") || responseName.equalsIgnoreCase("radio"))) { // The final true parameter is for disabling D Notes Element[] elements = cellFactory.createCellContentsForChecks(responseName, displayBean, displayBean.getMetadata().getResponseSet().getOptions().size(), ++tabindex, false, true); for (Element el : elements) { el = builderUtil.setClassNames(el); if (repeatFlag) { // el = repeatManager.addChildRepeatAttributes(el, repeatParentId, displayBean.getItem().getId(), null); } row.addContent(el); } // move to the next item continue; } td = new Element("td"); td = builderUtil.setClassNames(td); // Create cells within each row td = cellFactory.createCellContents(td, responseName, displayBean, ++tabindex, hasDiscrepancyMgt, hasDbFormValues, true); if (repeatFlag) { } row.addContent(td); if(j%maxColRow==0){ bodylist.add(row); row = new Element("tr"); if (repeatFlag) { repeatParentId = repeatParentId+uniqueId++; } } }// end for displayBean if(j%maxColRow!=0)bodylist.add(row); //Creating the first/main table if((repeatNumber > 1)||hasStoredRepeatedRows){ Element newRow = new Element("tr"); Element div = new Element("div"); div.setAttribute("id", "repeatCaption"); Element newCol = new Element("td"); Element strong = new Element("strong"); strong.addContent("Repeat: 1"); div.addContent(strong); newCol.addContent(div); newRow.addContent(newCol); table.addContent(newRow); } for(int k=0; k<headerlist.size();k++){ Element head = (Element)headerlist.get(k); Element body = (Element)bodylist.get(k); table.addContent(head); if(subHeadList.size()>0){ try{ Element subHead = (Element)subHeadList.get(k); table.addContent(subHead); }catch (IndexOutOfBoundsException IOB){ } } table.addContent(body); } // The final true parameter is for disabling D Note icons from // being clicked if (hasStoredRepeatedRows) { List storedRepeatedRows = builderUtil.generatePersistentMatrixRows(ordinalItemDataMap, currentDisplayItems, tabindex, repeatParentId, hasDiscrepancyMgt, true, maxColRow); // add these new rows to the table int count = 1; for(int l = 0; l<storedRepeatedRows.size();l++){ ++count; List<Element> rowsList = (ArrayList)storedRepeatedRows.get(l); divRoot.addContent(createTableWithData(rowsList, headerlist, subHeadList, count)); } } }// end for displayFormGroup XMLOutputter outp = new XMLOutputter(); Format format = Format.getPrettyFormat(); format.setOmitDeclaration(true); outp.setFormat(format); // The writer object contains the markup for one printable section writer = new StringWriter(); try { outp.output(doc, writer); } catch (IOException e) { e.printStackTrace(); } // The webPageBuilder object contains the markup for all of the // sections // in the print view webPageBuilder.append(writer.toString()); } return webPageBuilder.toString(); } /** * Sequentially create a String of XML representing all of the sections on a * Case Report Form, for the purpose of web-page display. * * @return A string representing the XML or XHTML. */ public String createMarkupNoDE() { // data associated with it, pass on the responsibility to another object ViewPersistanceHandler persistanceHandler = new ViewPersistanceHandler(); ViewBuilderPrintDecorator builderUtil = new ViewBuilderPrintDecorator(); // This object holds the printed output of the JDom Document object, // which represents // the XML for each section's HTML tables. The object is re-written // each time a new section is generated Writer writer = new StringWriter(); // This object contains all of the markup for all of the sections. StringBuilder webPageBuilder = new StringBuilder(); // Keep track of the section number so we can create page numbers int pageNumber = 0; if (isInternetExplorer) { for (DisplaySectionBean displaySecBean : this.displaySectionBeans) { this.reconfigureView = builderUtil.hasThreePlusColumns(displaySecBean); // Now the application knows that the view for at least one // section has to be // reformulated for IE if (reconfigureView) break; } } int uniqueId = 0; // Print all the sections of a group-type table for (DisplaySectionBean displaySecBean : this.displaySectionBeans) { // The CellFactoryPrintDecorator object that generates the content // for HTML table TD cells. CellFactoryPrintDecorator cellFactory = new CellFactoryPrintDecorator(); // The object that handles the repetition model attributes for the // HTML table elements RepeatManager repeatManager = new RepeatManager(); // These classes "decorate" the FormBeanUtil and ViewBuilderUtil // classes to // provide special services required in printing FormBeanUtilDecorator formUtilDecorator = new FormBeanUtilDecorator(); // Does this particular section have to be reconfigured for printing // in IE browsers? boolean changeHTMLForIE = false; if (reconfigureView) { // changeHTMLForIE = builderUtil.hasThreePlusColumns(displaySecBean); } ++pageNumber; sectionBean = displaySecBean.getSection(); if (involvesDataEntry) { List<ItemDataBean> itemDataBeans; persistanceHandler = new ViewPersistanceHandler(); itemDataBeans = persistanceHandler.fetchPersistedData(sectionBean.getId(), eventCRFbean.getId()); if (!itemDataBeans.isEmpty()) { hasDbFormValues = true; } persistanceHandler.setItemDataBeans(itemDataBeans); } // Keep track of whether a group has any repeat behavior; true or // false boolean repeatFlag; // The number of repeating table rows that the group will start // with. int repeatNumber; // the div tag that will be the root node for each printable section Element divRoot = new Element("div"); divRoot.setAttribute("id", ("toplevel" + pageNumber)); divRoot.setAttribute("class", "toplevel"); // remove float properties for IE browsers if (isInternetExplorer) { divRoot.setAttribute("style", "float:none"); } Document doc = new Document(divRoot); // Show the section's title, subtitle, or instructions builderUtil.showTitles(divRoot, sectionBean, pageNumber, isInternetExplorer); // One way to generate an id for the repeating tbody or tr element // The tabindex attribute for select and input tags int tabindex = 1; // Should discrepancy note icons be displayed boolean hasDiscrepancyMgt = false; StudyBean studBean = this.getStudyBean(); if (studBean != null && studBean.getStudyParameterConfig().getDiscrepancyManagement().equalsIgnoreCase("true")) { hasDiscrepancyMgt = true; } //Not to show discrepancy flags in the print crfs when there is no data hasDiscrepancyMgt=false; // Create a table for every DisplayItemGroupBean // A DisplayItemGroupBean contains an ItemGroupBean and // its list of DisplayItemBeans for (DisplayItemGroupBean displayItemGroup : displaySecBean.getDisplayFormGroups()) { ArrayList headerlist = new ArrayList(); ArrayList bodylist = new ArrayList(); ArrayList subHeadList = new ArrayList(); List<DisplayItemBean> currentDisplayItems = displayItemGroup.getItems(); // A Map that contains persistent (stored in a database), // repeated rows // in a matrix type table // The Map index is the Item id of the first member of the row; // the value is a List // of item beans that make up the row SortedMap<Integer, List<ItemDataBean>> ordinalItemDataMap = new TreeMap<Integer, List<ItemDataBean>>(); // Is this a persistent matrix table and does it already have // repeated rows // in the database? boolean hasStoredRepeatedRows = false; // Is this a non-group type table that shares the same section // as a group table? // boolean unGroupedTable = displayItemGroup.getItemGroupBean().getName().equalsIgnoreCase(BeanFactory.UNGROUPED); boolean unGroupedTable = displayItemGroup.getGroupMetaBean().isRepeatingGroup()?false:true; // Load any database values into the DisplayItemBeans if (hasDbFormValues) { currentDisplayItems = persistanceHandler.loadDataIntoDisplayBeans(currentDisplayItems, (!unGroupedTable)); /* * The highest number ordinal represents how many repeated * rows there are. If the ordinal in ItemDataBeans > 1, then * we know that the group has persistent repeated rows. Get * a structure that maps each ordinal (i.e., >= 2) to its * corresponding List of ItemDataBeans. Then iterate the * existing DisplayBeans, with the number of new rows * equaling the highest ordinal number minus 1 (meaning, the * first row represents the row of the group table that * would exist if the user displayed the table, but didn't * generate any new rows). For example, in a List of * ItemDataBeans, if the highest ordinal property among * these beans is 5, then the matrix table has 4 repeated * rows from the database. Provide each new row with its * values by using the ItemDataBeans. */ if (involvesDataEntry && !unGroupedTable && persistanceHandler.hasPersistentRepeatedRows(currentDisplayItems)) { hasStoredRepeatedRows = true; // if the displayitems contain duplicate item ids, then // these duplicates // represent repeated rows. Separate them into a Map of // new rows that // will be appended to the HTML table. ordinalItemDataMap = persistanceHandler.handleExtraGroupRows(); } }// end if hasDbFormValues // Does the table have a group header? String groupHeader = displayItemGroup.getGroupMetaBean().getHeader(); boolean hasGroupHeader = groupHeader != null && groupHeader.length() > 0; // Add group header, if there is one if (hasGroupHeader) { Element divGroupHeader = new Element("div"); // necessary? divGroupHeader.setAttribute("class", "aka_group_header"); Element strong = new Element("strong"); strong.setAttribute("style", "float:none"); strong.addContent(groupHeader); divGroupHeader.addContent(strong); divRoot.addContent(divGroupHeader); } Element tableDiv = new Element("div"); tableDiv.setAttribute("class", "tableDiv"); if (isInternetExplorer) { tableDiv.setAttribute("style", "float:none"); } divRoot.addContent(tableDiv); // This group represents "orphaned" items (those without a // group) if // the FormGroupBean has a group label of UNGROUPED Element orphanTable = null; if (unGroupedTable) { orphanTable = formUtilDecorator.createXHTMLTableFromNonGroup(currentDisplayItems, tabindex, hasDiscrepancyMgt, hasDbFormValues, true); // We have to track the point the tabindex has reached here // The tabindex will increment by the size of the // displayItemGroup List tabindex += currentDisplayItems.size(); tableDiv.addContent(orphanTable); continue; }// end if unGroupedTable uniqueId++; String repeatParentId = "repeatParent" + uniqueId; repeatNumber = displayItemGroup.getGroupMetaBean().getRepeatNum(); // If the form has repeat behavior, this number is > 0 // Do not allow repeat numbers < 1 repeatNumber = repeatNumber < 1 ? 1 : repeatNumber; // And a limit of 12 repeatNumber = repeatNumber > 12 ? 12 : repeatNumber; // This is always true during this iteration repeatFlag = true; Element table = createTable(); // add the thead element Element thead = new Element("tr"); tableDiv.addContent(table); // table.addContent(thead); // Does this group involve a Horizontal checkbox or radio // button? boolean hasResponseLayout = builderUtil.hasResponseLayout(currentDisplayItems); // add th elements to the thead element // We have to create an extra thead column for the Remove Row // button, if // the table involves repeating rows; thus the final boolean // parameter List<Element> thTags = repeatFlag ? createTheadContentsFromDisplayItems(currentDisplayItems, true) : createTheadContentsFromDisplayItems(currentDisplayItems, false); int i = 0; for (Element el : thTags) { i++; thead.addContent(el); if(i%maxColRow == 0) { headerlist.add(thead); thead = new Element("tr"); } } if(i%maxColRow!=0)headerlist.add(thead); // Make sure the layout for "horizontal" checkboxes or radios is // displayed // in this manner. if (hasResponseLayout) { addResponseLayoutRow(subHeadList, currentDisplayItems); } Element row; Element td; // For each row in the table row = new Element("tr"); // If the group has repeat behavior and repeats row by row, // then the // repetition model type attributes have to be added to the tr // tag if (repeatFlag && !(involvesDataEntry && hasStoredRepeatedRows)) { table = repeatManager.addParentRepeatAttributes(table, repeatParentId, repeatNumber, displayItemGroup.getGroupMetaBean().getRepeatMax()); } // The content for the table cells. For each item... int j = 0; for (DisplayItemBean displayBean : currentDisplayItems) { j++; // What type of input: text, radio, checkbox, etc.? String responseName = displayBean.getMetadata().getResponseSet().getResponseType().getName(); // We have to create cells in a different way if the input // is radio or checkbox, and the response_layout is // horizontal if (displayBean.getMetadata().getResponseLayout().equalsIgnoreCase("horizontal") && (responseName.equalsIgnoreCase("checkbox") || responseName.equalsIgnoreCase("radio"))) { // The final true parameter is for disabling D Notes Element[] elements = cellFactory.createCellContentsForChecks(responseName, displayBean, displayBean.getMetadata().getResponseSet().getOptions().size(), ++tabindex, false, true); for (Element el : elements) { el = builderUtil.setClassNames(el); if (repeatFlag) { el = repeatManager.addChildRepeatAttributes(el, repeatParentId, displayBean.getItem().getId(), null); } row.addContent(el); } // move to the next item continue; } td = new Element("td"); td = builderUtil.setClassNames(td); // Create cells within each row td = cellFactory.createCellContents(td, responseName, displayBean, ++tabindex, hasDiscrepancyMgt, hasDbFormValues, true); if (repeatFlag) { } row.addContent(td); if(j%maxColRow==0){ bodylist.add(row); row = new Element("tr"); if (repeatFlag) { repeatParentId = repeatParentId+uniqueId++; } } }// end for displayBean if(j%maxColRow!=0)bodylist.add(row); //Creating the first/main table if(hasStoredRepeatedRows){ Element newRow = new Element("tr"); Element div = new Element("div"); div.setAttribute("id", "repeatCaption"); Element newCol = new Element("td"); Element strong = new Element("strong"); strong.addContent("Repeat: 1"); div.addContent(strong); newCol.addContent(div); newRow.addContent(newCol); table.addContent(newRow); } if(!hasStoredRepeatedRows) for(int ii=0;ii<repeatNumber;ii++){ divRoot.addContent( createTableWithoutData(bodylist,headerlist,subHeadList,ii,unGroupedTable)); } // The final true parameter is for disabling D Note icons from // being clicked if (hasStoredRepeatedRows) { List storedRepeatedRows = builderUtil.generatePersistentMatrixRows(ordinalItemDataMap, currentDisplayItems, tabindex, repeatParentId, hasDiscrepancyMgt, true, maxColRow); // add these new rows to the table int count = 1; for(int l = 0; l<storedRepeatedRows.size();l++){ ++count; List<Element> rowsList = (ArrayList)storedRepeatedRows.get(l); divRoot.addContent(createTableWithData(rowsList, headerlist, subHeadList, count)); } } }// end for displayFormGroup XMLOutputter outp = new XMLOutputter(); Format format = Format.getPrettyFormat(); format.setOmitDeclaration(true); outp.setFormat(format); // The writer object contains the markup for one printable section writer = new StringWriter(); try { outp.output(doc, writer); } catch (IOException e) { e.printStackTrace(); } // The webPageBuilder object contains the markup for all of the // sections // in the print view webPageBuilder.append(writer.toString()); } return webPageBuilder.toString(); } // JN: So this displayFormGroups is being sent in a weird format, the list with values in currentDisplayItems // does not have the repeatnumber since metadata info is wrong, hence this weird way of going through the list. //Perhaps the better way is to fix the list itself, however the method is DisplaySectionBeanHandler.getDisplaySectionBeans is being used at several places and seems to be right, //there could be a issue with eventcrf which was never handled correctly hence this shortcut private int getRepeatFromPrevMeta(List<DisplayItemGroupBean> displayFormGroups) { if(displayFormGroups.size()>0) return displayFormGroups.get(0).getGroupMetaBean().getRepeatNum(); else return 0; } private Element createTableWithData(List<Element> rows, ArrayList headerList, ArrayList subHeaderList, int rep) { Element table = createTable(); Element newRow = new Element("tr"); Element newCol = new Element("td"); Element strong = new Element("strong"); strong.addContent("Repeat: "+rep); newCol.addContent(strong); newRow.addContent(newCol); table.addContent(newRow); for(int i=0; i<headerList.size();i++){ Element head = (Element)headerList.get(i); Element body = rows.get(i); table.addContent((Element)head.clone()); if(subHeaderList.size()>0){ try{ Element subHead = (Element)subHeaderList.get(i); table.addContent((Element)subHead.clone()); }catch (IndexOutOfBoundsException IOB){ } } table.addContent(body); } return table; } private Element createTableWithoutData(List<Element> rows, ArrayList headerList, ArrayList subHeaderList, int rep,boolean ungrouped) { // { Element table = createTable(); // if(headerList.size()>0){ table = createTable(); if(!ungrouped) { table.setAttribute("id","repeat"+rep); Element newCol = new Element("td"); Element strong = new Element("strong"); strong.setAttribute("style","aka_font_general"); strong.addContent("Repeat: "+(rep+1));//to avoid showing repeat 0; newCol.addContent(strong); Element newRow = new Element("tr"); newRow.addContent(newCol.cloneContent()); table.addContent(newRow.cloneContent()); strong.removeContent(); //} if(headerList.size()==0){ newRow.setAttribute("style","display:none;"); newCol.setAttribute("style","display:none;"); strong.setAttribute("style","display:none;"); table.setAttribute("style","display:none;"); } } for(int i=0; i<headerList.size();i++){ Element head = (Element)headerList.get(i); Element body = rows.get(i); table.addContent((Element)head.clone()); if(subHeaderList.size()>0){ try{ Element subHead = (Element)subHeaderList.get(i); table.addContent((Element)subHead.clone()); }catch (IndexOutOfBoundsException IOB){ } } table.addContent(body.cloneContent()); // } } return table; } private void addResponseLayoutRow(ArrayList subHeadList, List<DisplayItemBean> displayBeans) { Element thRow = new Element("tr"); String responseName; String responseLayout; ItemFormMetadataBean metaBean; // Now create the th row Element th2; ResponseSetBean respBean; ResponseOptionBean optBean; int j = 0; for (DisplayItemBean dBean : displayBeans) { j++; metaBean = dBean.getMetadata(); respBean = metaBean.getResponseSet(); responseName = respBean.getResponseType().getName(); if (responseName == null) { responseName = ""; } responseLayout = metaBean.getResponseLayout(); if (responseLayout == null) { responseLayout = ""; } // You could have a radio or checkbox whose layout is *not* // horizontal, // next to a rad or check *with* a horizontal layout. if ((responseName.equalsIgnoreCase("radio") || responseName.equalsIgnoreCase("checkbox")) && responseLayout.equalsIgnoreCase("horizontal")) { for (int i = 0; i < respBean.getOptions().size(); i++) { optBean = (ResponseOptionBean) respBean.getOptions().get(i); if (optBean != null) { th2 = createThCell(optBean.getText(), 1); // Add font for printing String classNames = th2.getAttribute("class").getValue(); classNames = classNames + " general_font"; th2.setAttribute("class", classNames); thRow.addContent(th2); } } } else { // create empty cells for non-radios or checks, or rads and // checks // without horizontal layout th2 = createThCell("", 1); thRow.addContent(th2); } if(j%maxColRow==0){ subHeadList.add(thRow); thRow = new Element("tr"); } } if(j%maxColRow!=0)subHeadList.add(thRow); // now add the final empty th cell for the row th2 = createThCell(); thRow.addContent(th2); } @Override public Element createTable() { Element tab = super.createTable(); return setClassNames(tab); } public Element createThCell(String cellText, int colSpan) { Element th = new Element("td"); th.setText(cellText); if (colSpan > 1) { th.setAttribute("colspan", colSpan + ""); } th.setAttribute("class", "aka_headerBackground aka_padding_large aka_cellBorders aka_font_general"); th.setAttribute("align", "center"); return th; } public Element createTHTagFromItemMeta(ItemFormMetadataBean itemFormBean) { // include quest number in the header Element thTag; String responseType = itemFormBean.getResponseSet().getResponseType().getName(); boolean hasQuestNumber = !"".equalsIgnoreCase(itemFormBean.getQuestionNumberLabel()); Element newSpan = new Element("span"); String header = itemFormBean.getHeader(); if (hasQuestNumber) { newSpan = new Element("span"); newSpan.setAttribute("style", "margin-right:1em"); newSpan.addContent(itemFormBean.getQuestionNumberLabel()); } if (header != null && header.length() == 0) { header = itemFormBean.getLeftItemText(); } // Implement colspan required for headers associated with // cells containing checkboxes or radio buttons if ((responseType.equalsIgnoreCase("radio") || responseType.equalsIgnoreCase("checkbox")) && itemFormBean.getResponseLayout().equalsIgnoreCase("horizontal")) { thTag = this.createThCell(header, itemFormBean.getResponseSet().getOptions().size()); } else { thTag = this.createThCell(header, 1); } if (hasQuestNumber) { thTag.addContent(0, newSpan); } // Add font for printing // String classNames = thTag.getAttribute("class").getValue(); // classNames = classNames + " general_font"; // thTag.setAttribute("class", classNames); return thTag; } public void createDarkBorders(Element element){ if(element == null) return; //remove the existing class attribute and replace it with one that specifies //darker cell borders element.removeAttribute("class"); //Is it a th or td tag? String cssRuleIdentifier = element.getName(); String cssClasses = CssRules.getClassNamesForTag(cssRuleIdentifier+" borders_on"); element.setAttribute("class",cssClasses); } public List<Element> createTheadContentsFromDisplayItems(List<DisplayItemBean> displayBeans, boolean generateExtraColumn) { List<Element> elements = new ArrayList<Element>(); ItemFormMetadataBean itemFormBean; // Get the names for the table's headers; // Use the item header first, then left item text if the // header is blank; add question number labels potentially for (DisplayItemBean displayBean : displayBeans) { itemFormBean = displayBean.getMetadata(); elements.add(createTHTagFromItemMeta(itemFormBean)); } // Create an extra column for the cells that contain a Remove Row button // if (generateExtraColumn) { // elements.add(this.createThCell("")); // } return elements; } @Override public Element setClassNames(Element styledElement) { String cssClasses = CssRules.getClassNamesForTag(styledElement.getName()); return cssClasses.length() == 0 ? styledElement : styledElement.setAttribute("class", cssClasses); } public SectionBean getSectionBean() { return sectionBean; } public void setSectionBean(SectionBean sectionBean) { this.sectionBean = sectionBean; } public boolean isInvolvesDataEntry() { return involvesDataEntry; } public void setInvolvesDataEntry(boolean involvesDataEntry) { this.involvesDataEntry = involvesDataEntry; } public EventCRFBean getEventCRFbean() { return eventCRFbean; } public void setEventCRFbean(EventCRFBean eventCRFbean) { this.eventCRFbean = eventCRFbean; } public StudyBean getStudyBean() { return studyBean; } public void setStudyBean(StudyBean studyBean) { this.studyBean = studyBean; } public boolean isInternetExplorer() { return isInternetExplorer; } public void setInternetExplorer(boolean internetExplorer) { isInternetExplorer = internetExplorer; } }