diff --git a/RequirementsManagement/src/edu/wpi/cs/wpisuitetng/modules/requirementsmanagement/gui/ViewPossibleSubReqTable.java b/RequirementsManagement/src/edu/wpi/cs/wpisuitetng/modules/requirementsmanagement/gui/ViewPossibleSubReqTable.java new file mode 100644 index 000000000..0677cd900 --- /dev/null +++ b/RequirementsManagement/src/edu/wpi/cs/wpisuitetng/modules/requirementsmanagement/gui/ViewPossibleSubReqTable.java @@ -0,0 +1,142 @@ +/******************************************************************************* + * Copyright (c) 2013 -- WPI Suite + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Josh + * Tim C + * James + * Jacob Palnick + * vpatara + ******************************************************************************/ + +package edu.wpi.cs.wpisuitetng.modules.requirementsmanagement.gui; + +import javax.swing.table.AbstractTableModel; + +/** + * Model for the possible sub-requirements table, which also tells whether a + * requirement can be attached as a child of this requirement, and vice versa + * + * @author vpatara + * @author Josh + * @author Tim C + * @author James + * @author Jacob Palnick + */ + +@SuppressWarnings("serial") +public class ViewPossibleSubReqTable extends AbstractTableModel { + + public static final int ID = 0; + public static final int NAME = 1; + public static final int DESCRIPTION = 2; + public static final int ITERATION = 3; + public static final int STATUS = 4; + public static final int PRIORITY = 5; + public static final int ESTIMATE = 6; + public static final int THIS_AS_CHILD = 7; + public static final int THIS_AS_PARENT = 8; + + /** name of the columns */ + private String[] columnNames = { "ID", "Name", "Description", "Iteration", + "Status", "Priority", "Estimate", "C", "P" }; + //first list is row, second list is column data + + /** data in each cell*/ + private Object[][] data = {}; + + /** + * get the number of columns + * + * @return the number of columns + */ + public int getColumnCount() { + return columnNames.length; + } + + /** + * get the number of rows + * + * @return the number of rows + */ + public int getRowCount() { + return data.length; + } + + /** + * get the name of a specified column + * + * @param col the column number + * @return the name of the column + */ + public String getColumnName(int col) { + return columnNames[col]; + } + + /** + * get the object in a cell + * + * @param row the row of the cell + * @param col the column of the cell + * @return the object at the cell + */ + public Object getValueAt(int row, int col) { + return data[row][col]; + } + + /** + * get the type of class in a column + * + * @param c the column number + * @return the kind of class in the column + */ + public Class getColumnClass(int c) { + return getValueAt(0, c).getClass(); + } + + /** + * see if a cell is editable, true if it is, false if it is not + * + * @param row the row of the cell + * @param col the column of the cell + * @return true if the cell is editable, false otherwise + */ + public boolean isCellEditable(int row, int col) { + return false; + } + + /** + * set the value at a cell + * + * @param value the value to set the cell + * @param row the row of the cell + * @param col the column of the cell + */ + public void setValueAt(Object value, int row, int col) { + data[row][col] = value; + fireTableCellUpdated(row, col); + } + + /** + * set data + * + * @param data the data to set + */ + public void setData(Object[][] data){ + this.data = data; + } + + /** + * Returns the data representation + * + * @return data + */ + public Object[][] getData() { + return data; + } +} diff --git a/RequirementsManagement/src/edu/wpi/cs/wpisuitetng/modules/requirementsmanagement/gui/viewrequirement/RequirementSubrequirementTab.java b/RequirementsManagement/src/edu/wpi/cs/wpisuitetng/modules/requirementsmanagement/gui/viewrequirement/RequirementSubrequirementTab.java index 21640fe0a..dd592721d 100644 --- a/RequirementsManagement/src/edu/wpi/cs/wpisuitetng/modules/requirementsmanagement/gui/viewrequirement/RequirementSubrequirementTab.java +++ b/RequirementsManagement/src/edu/wpi/cs/wpisuitetng/modules/requirementsmanagement/gui/viewrequirement/RequirementSubrequirementTab.java @@ -9,7 +9,7 @@ * Contributors: * Josh * Deniz - * JacobPalnick + * Jacob Palnick * vpatara ******************************************************************************/ @@ -35,6 +35,7 @@ import edu.wpi.cs.wpisuitetng.modules.requirementsmanagement.db.CurrentUserPermissionManager; import edu.wpi.cs.wpisuitetng.modules.requirementsmanagement.db.DB; import edu.wpi.cs.wpisuitetng.modules.requirementsmanagement.db.RequirementsCallback; +import edu.wpi.cs.wpisuitetng.modules.requirementsmanagement.gui.ViewPossibleSubReqTable; import edu.wpi.cs.wpisuitetng.modules.requirementsmanagement.gui.ViewReqTable; import edu.wpi.cs.wpisuitetng.modules.requirementsmanagement.gui.ViewReqTable.Mode; import edu.wpi.cs.wpisuitetng.modules.requirementsmanagement.models.RequirementModel; @@ -57,15 +58,19 @@ public class RequirementSubrequirementTab extends JPanel { public static final int STATUS = 4; public static final int PRIORITY = 5; public static final int ESTIMATE = 6; - public static final int RELEASE = 7; - public static final int ROWS = 7; + public static final int COLUMNS = 7; + + // These two are for the possible sub-requirement table + public static final int THIS_AS_CHILD = 7; + public static final int THIS_AS_PARENT = 8; + public static final int EXTENDED_COLUMNS = 9; /** the panel this is shown in */ RequirementsPanel parent; /** tableModle to display current subrequirements */ ViewReqTable subrequirementsTableModel; /** tableModel to display other possible subrequirements */ - ViewReqTable possibleSubrequirementsTableModel; + ViewPossibleSubReqTable possibleSubrequirementsTableModel; /** tableModle to display current subrequirements */ JTable subrequirementsTable; /** tableModel to display other possible subrequirements */ @@ -80,6 +85,16 @@ public class RequirementSubrequirementTab extends JPanel { JButton setParentButton; JButton removeChildButton; + /** Direct (immediate) parents of this requirement */ + private ArrayList directParentIdList; + /** All parents of this requirement (including parent's parent) */ + private ArrayList allParentIdList; + + /** Direct (immediate) children of this requirement (this = subrequirements)*/ + private ArrayList directSubIdList; + /** All children (descendants) of this requirement (including child's child) */ + private ArrayList allSubIdList; + /** * Constructs a panel for notes * @@ -129,8 +144,7 @@ public void mousePressed(MouseEvent e) { subrequirementTableScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED); subrequirementTableScrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); - possibleSubrequirementsTableModel = new ViewReqTable(); - possibleSubrequirementsTableModel.setMode(Mode.VIEW); + possibleSubrequirementsTableModel = new ViewPossibleSubReqTable(); possibleSubrequirementsTable = new JTable(possibleSubrequirementsTableModel);// { possibleSubrequirementsTable.setPreferredScrollableViewportSize(new Dimension(500, 100)); possibleSubrequirementsTable.setFillsViewportHeight(true); @@ -250,18 +264,15 @@ public void actionPerformed(ActionEvent e) { * @param selectedId the id of the selected requirement */ private void updateSelectedPossible(String selectedId) { - if (selectedId == null || selectedId.equals("") || parent.model.getStatus() == RequirementStatus.COMPLETE || parent.model.getStatus() == RequirementStatus.DELETED || parent.submit.getText().equals("Save")) { + if (selectedId == null || selectedId.equals("") + || parent.model.getStatus() == RequirementStatus.COMPLETE + || parent.model.getStatus() == RequirementStatus.DELETED + || parent.submit.getText().equals("Save")) { addChildButton.setEnabled(false); setParentButton.setEnabled(false); } else { - addChildButton.setEnabled(!subIdList.contains(selectedId)); - setParentButton.setEnabled(!parentIdList.contains(selectedId)); - for (String req : subrequirements) { - if(req.equals(selectedId)) { - addChildButton.setEnabled(false); - setParentButton.setEnabled(false); - } - } + addChildButton.setEnabled(!directSubIdList.contains(selectedId) && !allParentIdList.contains(selectedId)); + setParentButton.setEnabled(!directParentIdList.contains(selectedId) && !allSubIdList.contains(selectedId)); } } @@ -270,18 +281,7 @@ private void updateSelectedPossible(String selectedId) { * @param selectedId the id of the selected requirement */ private void updateSelectedSub(String selectedId) { - if (selectedId == null || selectedId.equals("")) { - removeChildButton.setEnabled(false); - } else { - removeChildButton.setEnabled(true); -// setParrentButton.setEnabled(true); -// for (String req : subrequirements) { -// if(req.equals(selectedId)) { -// addChildButton.setEnabled(false); -// setParrentButton.setEnabled(false); -// } -// } - } + removeChildButton.setEnabled(selectedId != null && !selectedId.equals("")); } @Override @@ -339,10 +339,7 @@ private String getSelectedPosId() { return ""; } } - - ArrayList parentIdList; - ArrayList subIdList; - + /** * * Callback to populate the table with all the requirements @@ -369,32 +366,74 @@ public UpdateTablesCallback(String selectedSub, String selectedPos) { public void callback(List reqs) { System.out.println("updateTablesCallback "+reqs.size()); if (reqs.size() > 0) { - subIdList = new ArrayList(); - parentIdList = new ArrayList(); - - //get a list of ids of requirements that are already sub requirements + directSubIdList = new ArrayList(); + allSubIdList = new ArrayList(); + directParentIdList = new ArrayList(); + allParentIdList = new ArrayList(); + + // For simplicity, assume this requirement is both its own sub and parent + directSubIdList.add(parent.model.getId() + ""); + directParentIdList.add(parent.model.getId() + ""); + + // Collects its immediate sub-requirements (children), + // i.e., requirements that are already this one's sub-requirements + directSubIdList.addAll(subrequirements); + + // Collects its immediate parents for(RequirementModel req : reqs) { - for(String subId : req.getSubRequirements()) { - if(!subIdList.contains(subId)) { - subIdList.add(subId); + String parentId = req.getId() + ""; + String thisId = parent.model.getId() + ""; + + // Add it if it's a parent but not yet added + if(!directParentIdList.contains(parentId) && + req.getSubRequirements().contains(thisId)) { + directParentIdList.add(parentId); + } + } + + // Get a list of all children of this requirement (including subs of subs) + allSubIdList.addAll(directSubIdList); + boolean changed = true; + while(changed) { + changed = false; + + // For each requirement that is a descendant (not necessary direct) ... + for(RequirementModel thisNode : reqs) { + if(allSubIdList.contains(thisNode.getId() + "")) { + // Add this sub's subs + for(String subId : thisNode.getSubRequirements()) { + if(!allSubIdList.contains(subId)) { + allSubIdList.add(subId); + changed = true; + } + } } } } - - //get a list of the parents of this requirement - String currentChildId = parent.model.getId()+""; - String nextChildId = ""; - while(currentChildId != null && !currentChildId.equals("")) { - nextChildId = ""; - for(RequirementModel req : reqs) { - if(req.getSubRequirements().contains(currentChildId)) { - nextChildId = req.getId()+""; - parentIdList.add(nextChildId); + + // Get a list of the parents (ancestors) of this requirement + allParentIdList.addAll(directParentIdList); + changed = true; + while(changed) { + changed = false; + + // Check for all requirements not yet in the parent list... + for(RequirementModel potentialParent : reqs) { + if (!allParentIdList.contains(potentialParent.getId() + "")) { + + // Check if this requirement is a parent of any one already in the list + for(String parentId : allParentIdList) { + // If so, add that requirement into the list + if(potentialParent.getSubRequirements().contains(parentId)) { + allParentIdList.add(potentialParent.getId() + ""); + changed = true; + break; + } + } } } - currentChildId = nextChildId; } - + // put the data in the table ArrayList subEntriesList = new ArrayList(); ArrayList posEntriesList = new ArrayList(); @@ -407,8 +446,8 @@ public void callback(List reqs) { String priority = (req.getPriority() == null ? "" : req.getPriority().toString()); String estimate = req.getEstimate()+""; - if (subrequirements.contains(id)) { - Object[] subEntry = new Object[ROWS]; + if (subrequirements.contains(id)) { // same as directSubIdList.contains(id) + Object[] subEntry = new Object[COLUMNS]; subEntry[ID] = id; subEntry[NAME] = name; subEntry[DESCRIPTION] = description; @@ -417,15 +456,17 @@ public void callback(List reqs) { subEntry[PRIORITY] = priority; subEntry[ESTIMATE] = estimate; subEntriesList.add(subEntry); - } else { - //TODO make sure the requirement is not a parent of the current requirement - if (req.getId() != parent.model.getId() && - !subIdList.contains(id) && - !parentIdList.contains(id) && - (req.getStatus() == RequirementStatus.NEW || - req.getStatus() == RequirementStatus.OPEN || - req.getStatus() == RequirementStatus.IN_PROGRESS)) { - Object[] posEntry = new Object[ROWS]; + } else if(req.getId() != parent.model.getId() && + (req.getStatus() == RequirementStatus.NEW || + req.getStatus() == RequirementStatus.OPEN || + req.getStatus() == RequirementStatus.IN_PROGRESS)) { + + // Determines possibilities for this requirement + boolean canThisBeChild = (!directSubIdList.contains(id) && !allParentIdList.contains(id)); + boolean canThisBeParent = (!directParentIdList.contains(id) && !allSubIdList.contains(id)); + + if (canThisBeChild || canThisBeParent) { + Object[] posEntry = new Object[EXTENDED_COLUMNS]; posEntry[ID] = id; posEntry[NAME] = name; posEntry[DESCRIPTION] = description; @@ -433,10 +474,14 @@ public void callback(List reqs) { posEntry[STATUS] = status; posEntry[PRIORITY] = priority; posEntry[ESTIMATE] = estimate; + posEntry[THIS_AS_CHILD] = canThisBeChild; + posEntry[THIS_AS_PARENT] = canThisBeParent; posEntriesList.add(posEntry); } else { System.out.println("bad: " + id); } + } else { + System.out.println("bad: " + id); } } @@ -460,7 +505,7 @@ public void callback(List reqs) { TableColumn column = null; TableColumn column2 = null; - for (int i = 0; i < ROWS; i++) { + for (int i = 0; i < COLUMNS; i++) { column = subrequirementsTable.getColumnModel().getColumn(i); column2 = possibleSubrequirementsTable.getColumnModel().getColumn(i); if (i == ID) { @@ -480,6 +525,12 @@ else if (i == DESCRIPTION) { column2.setPreferredWidth(200); } } + + // Sets the sizes for the (two) new columns + for (int i = COLUMNS; i < EXTENDED_COLUMNS; i++) { + possibleSubrequirementsTable.getColumnModel().getColumn(i).setPreferredWidth(30); + } + subrequirementTableScrollPane.setEnabled(true); possibleSubrequirementTableScrollPane.setEnabled(true); subrequirementsTable.setEnabled(true);