ExecuteQuery.run이 호출되어 사용자가 조회를 선택하고 실행할 수 있습니다. 이 예제에서, ViewRecord.Viewer라고 하는 ExeuteQuerty.Viewer의 실제 인스턴스와 함께 ExecuteQuerty.run 메소드가 제공됩니다. 이로 인해 열기 단추가 결과 세트 표시에 나타나며, 클릭하면 Viewer.view 메소드가 호출됩니다. Viewer.view 메소드(아래에 정의되어 있음)는 선택된 결과 세트 행과 연관되는 자원에 대한 프록시를 전달합니다. 프록시는 CqRowData.getRecord() 메소드를 사용하여 얻습니다.
따라서 이 예제의 핵심은 Viewer.view 메소드에 임베드됩니다.
static class Viewer implements ExecuteQuery.Viewer { Viewer(CqProvider provider) { m_provider = provider; } /** * @see com.ibm.rational.stp.client.samples.ExecuteQuery.Viewer#view(com.ibm.rational.wvcm.stp.cq.CqRecord) */ public JFrame view(CqRecord record) { if (record != null) try { record = (CqRecord)record.doReadProperties(RECORD_PROPERTIES); return showRecord("View: ", record, null); } catch (WvcmException ex){ ex.printStackTrace(); } return null; } /** * Displays the content of an Attachment resource in a text window. * * @param attachment An Attachment proxy for the attachment to be * displayed. */ public void view(CqAttachment attachment) { if (attachment != null) try{ File file = File.createTempFile("attach", "tmp"); attachment.doReadContent(file.getAbsolutePath(), null); BrowserDataModel.showFile(attachment.getDisplayName(), file); } catch(Throwable ex) { Utilities.exception(null, "View Attachment", ex); } } /** * Displays the ALL_FIELD_VALUES property of a record resource in a * table. The columns of the table are determined by the content of the * {@link #fieldMetaProperties} array. The display of most objects is * implemented by the object's own toString() method. * * @param title The title string for the window that contains the table * @param record The Record proxy for the record to be displayed. Must * define the ALL_FIELD_VALUES property and the FieldValues * in that property must define the meta-properties listed in * the {@link #fieldMetaProperties} array. * @param future Additional window components to be displayed along with * the property table. (Used by extensions to this example). * @return A RecordFrame structure containing the GUI components created * by this method. * @throws WvcmException */ RecordFrame showRecord(String title, CqRecord record, JComponent[] future) throws WvcmException { final StpProperty.List<CqFieldValue<?>> fields = record.getAllFieldValues(); // Define a table model in which each row is a property of the // record resource and each column is a meta-property of the // property, such as its name, type, and value; TableModel dataModel = new AbstractTableModel() { private static final long serialVersionUID = 1L; public int getColumnCount() { return fieldMetaProperties.length; } public int getRowCount() { return fields.size();} public Object getValueAt(int row, int col) { try { Object val = fields.get(row) .getMetaProperty((MetaPropertyName<?>) fieldMetaProperties[col].getRoot()); if (val instanceof CqRecord) return ((CqRecord)val).getUserFriendlyLocation() .getName(); else if (val instanceof CqAttachmentFolder) return ((CqAttachmentFolder)val) .getAttachmentList().size() + " attachments"; else return val; } catch(Throwable ex) { if (ex instanceof StpException) { return ((StpException)ex).getStpReasonCode(); } else { String name = ex.getClass().getName(); return name.substring(name.lastIndexOf(".")+1); } } } public String getColumnName(int col) { return fieldMetaProperties[col].getRoot().getName(); } }; // Define the display layout final JTable table = new JTable(dataModel); final JPanel panel = new JPanel(new BorderLayout()); final JPanel buttons = new JPanel(new FlowLayout()); final JButton button = new JButton("View"); final RecordFrame frame = new RecordFrame(title + record.getUserFriendlyLocation().toString(), table, fields); // Add a button for viewing a selected record or attachment field buttons.add(button, BorderLayout.SOUTH); button.setEnabled(false); button.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent arg0) { int[] selected = table.getSelectedRows(); for (int i =0; i < selected.length; ++i) { int row = selected[i]; if (isAttachmentList(fields, row)) { view(selectAttachment(frame, fields, row, "View")); } else { view(getRecordReferencedAt(fields, row)); } } } }); // Add more buttons (used by later examples) if (future != null) for(int i = 0; i < future.length; ++i) buttons.add(future[i]); table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); // Ask to be notified of selection changes and enable the view button // only if a record-valued field or attachment field is selected ListSelectionModel rowSM = table.getSelectionModel(); rowSM.addListSelectionListener(new ListSelectionListener() { public void valueChanged(ListSelectionEvent e) { if (!e.getValueIsAdjusting()){ int[] selected = table.getSelectedRows(); button.setEnabled(false); for (int i=0; i <selected.length; ++i) if (getRecordReferencedAt(fields, selected[i]) != null || isAttachmentList(fields, selected[i])) { button.setEnabled(true); break; } } } }); panel.add(new JScrollPane(table), BorderLayout.CENTER); panel.add(buttons, BorderLayout.SOUTH); frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); frame.setContentPane(panel); frame.setBounds(g_windowX += 10, g_windowY += 10, 600, 300); frame.setVisible(true); return frame; } protected CqProvider m_provider; } /** * Properties to be requested from each record field value, including * specific additional information for attachments */ static final PropertyRequest VALUE_PROPERTIES = new PropertyRequest(StpResource.USER_FRIENDLY_LOCATION, CqAttachmentFolder.ATTACHMENT_LIST .nest(CqAttachment.DISPLAY_NAME, CqAttachment.FILE_NAME, CqAttachment.FILE_SIZE, CqAttachment.DESCRIPTION)); /** The field meta-properties to be requested and displayed */ static final NestedPropertyName[] fieldMetaProperties = new PropertyRequest(CqFieldValue.NAME, CqFieldValue.REQUIREDNESS, CqFieldValue.TYPE, CqFieldValue.VALUE.nest(VALUE_PROPERTIES)).toArray(); /** * The PropertyRequest to use when reading data from a record to be * displayed by this viewer. Note the level of indirection used to request * the meta-properties of the fields in the ALL_FIELD_VALUES list rather * than those meta-properties of the ALL_FIELD_VALUES property itself. */ final static PropertyRequest RECORD_PROPERTIES = new PropertyRequest(CqRecord.USER_FRIENDLY_LOCATION, CqRecord.ALL_FIELD_VALUES .nest(StpProperty.VALUE.nest(fieldMetaProperties))); /** * Examines the property value of a field and, if it references a record, * returns a proxy for the referenced record. Otherwise it returns null. * @param fields The Property.List to examine. * @param row The index of the element in the list to examine. * @return A Record proxy if the field references a record; null otherwise */ static CqRecord getRecordReferencedAt(StpProperty.List<CqFieldValue<?>> fields, int row) { try { CqFieldValue field = fields.get(row); if (field.getFieldType() == ValueType.RESOURCE && field.getValue() instanceof CqRecord) return (CqRecord)field.getValue(); } catch (WvcmException ex) { ex.printStackTrace(); } return null; } /** * Whether or not the indicated field is an attachment field. * @param fields The Property.List to examine. * @param row The index of the element in the list to examine. * @return true iff the field at the given index is an attachment field */ static boolean isAttachmentList(StpProperty.List<CqFieldValue<?>> fields, int row) { if (row >= 0) try { CqFieldValue field = fields.get(row); return field.getFieldType() == ValueType.ATTACHMENT_LIST; } catch (WvcmException ex) { ex.printStackTrace(); } return false; } /** * Presents to the user a list of the attachments associated with a * specified field of a record and allows the user to select one. * * @param frame The parent frame for the dialog generated by this method. * @param fields The Property.List to examine. * @param row The index of the element in the list to examine. * @param op A string identifying the operation that will be performed on * the selected attachment. * @return An Attachment proxy for the selected attachment; null if the user * chooses to make no selection. */ static CqAttachment selectAttachment(Component frame, StpProperty.List<CqFieldValue<?>> fields, int row, String op) { CqFieldValue field = fields.get(row); try { CqAttachmentFolder folder = (CqAttachmentFolder)field.getValue(); ResourceList<CqAttachment> attachments = setUserFriendlyLocation (folder.doReadProperties(ATTACHMENT_PROPERTIES) .getProperty(CqAttachmentFolder.ATTACHMENT_LIST)); if (attachments.size() > 0) { CqAttachment attachment = (CqAttachment) JOptionPane .showInputDialog(frame, "Choose an Attachment to " + op, op + " Attachment", JOptionPane.INFORMATION_MESSAGE, null, attachments.toArray(), attachments.get(0)); return attachment; } } catch(Throwable t) { Utilities.exception(frame, op + " Attachment", t);} return null; } /** * The attachment properties to be displayed in the attachment selection * list generated by {@link #selectAttachment}. */ final static PropertyRequest ATTACHMENT_PROPERTIES = new PropertyRequest(CqAttachmentFolder.ATTACHMENT_LIST .nest(CqAttachment.DISPLAY_NAME, CqAttachment.FILE_NAME, CqAttachment.FILE_SIZE, CqAttachment.DESCRIPTION, CqAttachment.USER_FRIENDLY_LOCATION)); /** * The main program for the ViewRecord example. Instantiates a Provider and * then invokes the ExecuteQuery example, passing in a version of Viewer * that displays fields of a ClearQuest record. * @param args not used. */ public static void main(String[] args) { try { CqProvider provider = Utilities.getProvider().cqProvider(); ExecuteQuery.run("View Record", provider, new Viewer(provider)); } catch(Throwable ex) { Utilities.exception(null, "View Record", ex); System.exit(0); } } /** * An extension of JFrame for the record field display, * exposing to clients the JTable component of the frame and * the field list that is being displayed in the table. */ static class RecordFrame extends JFrame { RecordFrame(String title, JTable table, StpProperty.List fields) { super(title); m_table = table; m_fields = fields; } JTable m_table; StpProperty.List m_fields; private static final long serialVersionUID = 1L; } /** X offset for the next window to be displayed */ private static int g_windowX = 200; /** Y offset for the next window to be displayed */ private static int g_windowY = 200;
이 예제에서, ViewRecord.Viewer는 조회에서 리턴된 레코드를 표시할 뿐만 아니라 선택된 레코드 필드에 의해 참조되는 레코드를 보고 레코드 필드에 첨부된 파일을 보기 위해 사용됩니다. 사용자는 이 기능을 사용하여 하나의 레코드에서 다른 레코드로의 참조를 통해 찾아볼 수 있습니다.
ViewRecord.view(CqRecord)는 데이터베이스의 레코드와 뷰어에 사용된 각 필드의 메타 특성에서 모든 필드를 읽고 채워진 프록시를 showRecord 메소드로 전달합니다. 뷰어는 ClearQuest® 레코드의 ALL_FIELD_VALUES 특성을 사용하여 레코드에 있는 모든 필드 목록을 가져옵니다. 필드마다, NAME, REQUIREDNESS, TYPE 및 VALUE 메타 특성이 요청됩니다. 이 메타 특성 요청은 메타 특성이 ALL_FIELD_VALUES 특성 자체가 아니라 ALL_FIELD_VALUES 특성의 값에 대해 얻어지도록 다른 VALUE 메타 특성 요청 아래에 중첩됩니다. (RECORD_PROPERTIES, VALUE_PROPERTIES 및 fieldMetaProperties 선언을 참조하십시오.)
필드가 첨부 필드인 경우 값의 ATTACHMENT_LIST 특성도 요청됩니다. (필드가 첨부 필드가 아닌 경우 이 특성 요청은 실패하지만 필드가 첨부 필드인 경우에만 이 특성에 액세스하므로, 이 실패로 예외가 발생하지는 않습니다.)
ViewRecord.showRecord는 ExecuteQuery.showResults와 동일한 Swing GUI 컴포넌트 및 구조를 사용합니다. 테이블의 행 및 열의 컨텐츠만 다릅니다. 이러한 경우 각 행은 CqFieldValue 오브젝트로 표시되는 레코드의 필드입니다. 각각의 열은 필드의 메타 특성입니다. 일반 StpProperty.getMetaProperty 인터페이스를 사용하여 각 필드의 CqFieldValue/StpProperty 구조에서 메타 특성 값을 페치합니다. 두 가지 예외에서, 각 메타 특성 값에 대한 toString() 메소드는 레코드 뷰에서의 메타 특성 이미지 생성에 의존합니다. 레코드 자원의 경우 출력에서의 클러터를 줄이기 위해 USER_FRIENDLY_LOCATION 특성의 이름 필드만 표시됩니다. 첨부 필드의 경우 첨부 수만 표시되고 각각의 첨부 이름은 표시되지 않습니다.
필드 유형 RESOURCE_LIST, JOURNAL, STRING_LIST 및 STRING의 표시에도 특별한 주위를 기울일 수 있습니다. 이는 리더를 위한 연습용으로 남겨집니다.
첨부 필드가 선택되고 보기 단추를 클릭한 경우 selectAttachment가 호출되고 해당 결과는 ViewRecord.view(CqAttachment)로 전달됩니다. selectAttachment 메소드는 JOptionPane.showInputDialog를 다시 사용하여 선택된 필드와 연관되는 첨부 목록을 사용자에게 제시합니다. 첨부 필드의 값은 첨부 폴더 자원입니다. 필드와 연관되는 첨부사항은 해당 첨부 폴더의 바인드된 구성원입니다.
ViewRecord.view(CqAttachment)는 CqAttachment.doReadContent를 사용하여 데이터베이스에서 임시 파일로 첨부된 파일을 읽은 후 유틸리티 메소드(모든 Swing 코드)를 호출하여 사용자에게 파일을 표시합니다.
ViewRecord.Viewer는 또한 별도의 창에서 RESOURCE_LIST 값의 표시를 지원해야 합니다. 그러나 이 역시 리더를 위한 연습용으로 남겨집니다.