1 /* 2 * UnBBayes 3 * Copyright (C) 2002, 2008 Universidade de Brasilia - http://www.unb.br 4 * 5 * This file is part of UnBBayes. 6 * 7 * UnBBayes is free software: you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation, either version 3 of the License, or 10 * (at your option) any later version. 11 * 12 * UnBBayes is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with UnBBayes. If not, see <http://www.gnu.org/licenses/>. 19 * 20 */ 21 package unbbayes.gui.table; 22 23 import java.awt.Color; 24 import java.text.NumberFormat; 25 import java.util.ArrayList; 26 import java.util.List; 27 import java.util.Locale; 28 29 import javax.swing.JDialog; 30 import javax.swing.JScrollPane; 31 import javax.swing.JTable; 32 import javax.swing.table.DefaultTableModel; 33 34 import unbbayes.prs.Node; 35 import unbbayes.prs.bn.PotentialTable; 36 37 public class GUIPotentialTable { 38 39 private PotentialTable potentialTable; 40 41 public GUIPotentialTable(PotentialTable potentialTable) { 42 this.potentialTable = potentialTable; 43 } 44 /** 45 * This method is responsible to represent the potential table as a JTable. 46 * @return Returns the JTable representing this potential table. 47 * TODO MIGRATE TO A DIFFERENT CLASS - GUI.TABLE.PROBABILISTICTABLE 48 */ 49 public JTable makeTable() { 50 JTable table; 51 int nStates = 1; 52 // Number of variables 53 int nVariables = potentialTable.variableCount(); 54 Node node = (Node)potentialTable.getVariableAt(0); 55 NumberFormat df = NumberFormat.getInstance(Locale.getDefault()); 56 df.setMaximumFractionDigits(4); 57 58 // calculate the number of states by multiplying the number of 59 // states that each father (variables) has. Where variable 0 is the 60 // node itself. That is why we divide the table size by the number 61 // of states in the node itself. 62 /* 63 * Ex: states = 12 / 3; 64 * 65 * |------------------------------------------------------| 66 * | Father 2 | State 1 | State 2 | 67 * |--------------|-------------------|-------------------| 68 * | Father 1 | State 1 | State 2 | State 1 | State 2 | 69 * |------------------------------------------------------| 70 * | Node State 1 | 1 | 1 | 1 | 1 | 71 * | Node State 2 | 0 | 0 | 0 | 0 | 72 * | Node State 3 | 0 | 0 | 0 | 0 | 73 * |------------------------------------------------------| 74 * 75 */ 76 nStates = potentialTable.tableSize() / node.getStatesSize(); 77 78 // the number of rows is the number of states the node has. 79 int rows = node.getStatesSize(); 80 81 // the number of columns is the number of states that we calculated 82 // before plus one that is the column where the fathers names and 83 // the states of the node itself will be placed. 84 int columns = nStates + 1; 85 86 // Constructing the data of the data model. 87 /* 88 * Ex: data[3][4 + 1] 89 * |------------------------------------------------------| 90 * | Node State 1 | 1 | 1 | 1 | 1 | 91 * | Node State 2 | 0 | 0 | 0 | 0 | 92 * | Node State 3 | 0 | 0 | 0 | 0 | 93 * |------------------------------------------------------| 94 */ 95 String[][] data = new String[rows][columns]; 96 97 // Constructing the first header's row 98 /* 99 * Ex: Following the example above this is the first header's row. 100 * 101 * |--------------|-------------------|-------------------| 102 * | Father 1 | State 1 | State 2 | State 1 | State 2 | 103 * |------------------------------------------------------| 104 * 105 */ 106 String[] column = new String[data[0].length]; 107 Node firtHeaderNode; 108 // If there is no father, this is going to be the first header's 109 // row: 110 /* 111 * |-----------|---------------| 112 * | State | Probability | 113 * |---------------------------| 114 * 115 */ 116 if (nVariables == 1) { 117 column[0] = "State"; 118 column[1] = "Probability"; 119 } else { 120 firtHeaderNode = (Node)potentialTable.getVariableAt(1); 121 /* 122 * Ex: Here we get the variable "Father 1" and set its name in 123 * the header. 124 * 125 * |--------------| 126 * | Father 1 | 127 * |--------------- 128 * 129 */ 130 column[0] = firtHeaderNode.getName(); 131 for (int i = 0; i < data[0].length - 1; i++) { 132 if (nVariables > 1) { 133 // Reapeats all states in the node until there are cells to 134 // fill. 135 /* 136 * Ex: Following the example above. Here the states go. 137 * 138 * |-------------------|-------------------| 139 * | State 1 | State 2 | State 1 | State 2 | 140 * ----------------------------------------| 141 * 142 */ 143 column[i + 1] = firtHeaderNode.getStateAt(i % firtHeaderNode.getStatesSize()); 144 } 145 } 146 } 147 148 // Filling the data of the data model. 149 /* 150 * Ex: Fill the data[3][5] constructed above. 151 * |------------------------------------------------------| 152 * | Node State 1 | 1 | 1 | 1 | 1 | 153 * | Node State 2 | 0 | 0 | 0 | 0 | 154 * | Node State 3 | 0 | 0 | 0 | 0 | 155 * |------------------------------------------------------| 156 */ 157 // The values are arranged in the potential table as a vector. 158 /* 159 * Ex: This would be the vector in the potential table. 160 * |-------------------------------------------------------------------| 161 * | Vector Position | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 162 * | Vector Value | 1 | 0 | 0 | 1 | 0 | 0 | 1 | 0 | 0 | 1 | 0 | 0 | 163 * |-------------------------------------------------------------------| 164 */ 165 // So, for each column we jump the number of values corresponding 166 // that column, that is, the number of rows. 167 for (int c = 1, n = 0; c < columns; c++, n += rows) { 168 for (int r = 0; r < rows; r++) { 169 // So, data[0][3] = vector[6 + 0] = 1 170 data[r][c] = "" + "" + df.format(potentialTable.getValue(n + r)); 171 } 172 } 173 // Now that we filled the values, we are going to put this node's 174 // states name. 175 /* 176 * Ex: Fill the data[i][0] constructed above, that is, its states 177 * name. 178 * |--------------- 179 * | Node State 1 | 180 * | Node State 2 | 181 * | Node State 3 | 182 * |--------------- 183 */ 184 for (int i = 0; i < rows; i++) { 185 data[i][0] = node.getStateAt(i); 186 } 187 188 // Constructing the table so far. 189 /* 190 * Ex: The table so far, following the example above. 191 * 192 * |--------------|-------------------|-------------------| 193 * | Father 1 | State 1 | State 2 | State 1 | State 2 | 194 * |------------------------------------------------------| 195 * | Node State 1 | 1 | 1 | 1 | 1 | 196 * | Node State 2 | 0 | 0 | 0 | 0 | 197 * | Node State 3 | 0 | 0 | 0 | 0 | 198 * |------------------------------------------------------| 199 * 200 */ 201 DefaultTableModel model = new DefaultTableModel(); 202 model.setDataVector(data, column); 203 table = new JTable(); 204 // Setup to allow grouping the header. 205 table.setColumnModel(new GroupableTableColumnModel()); 206 table.setTableHeader(new GroupableTableHeader( 207 (GroupableTableColumnModel) table.getColumnModel())); 208 table.setModel(model); 209 210 // Setup Column Groups 211 GroupableTableColumnModel cModel = (GroupableTableColumnModel) table 212 .getColumnModel(); 213 ColumnGroup cNodeGroup = null; 214 ColumnGroup cNodeTempGroup = null; 215 ColumnGroup cGroup = null; 216 List<ColumnGroup> cGroupList = new ArrayList<ColumnGroup>(); 217 List<ColumnGroup> previousCGroupList = new ArrayList<ColumnGroup>(); 218 int columnIndex; 219 boolean firstNode = true; 220 int sizeColumn = 1; 221 // Sets default color for parents name in first column. 222 /* 223 * |--------------- 224 * | Father 2 | 225 * |--------------| 226 * | Father 1 | 227 * |--------------- 228 * 229 */ 230 cModel.getColumn(0).setHeaderRenderer(new GroupableTableCellRenderer()); 231 // Sets default color for node's states 232 /* 233 * |--------------- 234 * | Node State 1 | 235 * | Node State 2 | 236 * | Node State 3 | 237 * |--------------- 238 * 239 */ 240 cModel.getColumn(0).setCellRenderer(new GroupableTableCellRenderer(Color.BLACK, Color.YELLOW)); 241 // Fill all other headers, but the first (that has already been 242 // set). It ignores k = 0 (the node itself) and k = 1 (the fist 243 // father). 244 for (int k = 2; k < nVariables; k++) { 245 Node parent = (Node)potentialTable.getVariableAt(k); 246 int nPreviousParentStates = potentialTable.getVariableAt(k-1).getStatesSize(); 247 sizeColumn *= nPreviousParentStates; 248 // Set the node name as a header in the first column 249 if (!firstNode) { 250 cNodeTempGroup = cNodeGroup; 251 cNodeGroup = new ColumnGroup(new GroupableTableCellRenderer(), parent.getName()); 252 cNodeGroup.add(cNodeTempGroup); 253 } else { 254 cNodeGroup = new ColumnGroup(new GroupableTableCellRenderer(), parent.getName()); 255 cNodeGroup.add(cModel.getColumn(0)); 256 } 257 columnIndex = 1; 258 cGroup = null; 259 while (columnIndex <= nStates) { 260 for (int i = 0; i < parent.getStatesSize(); i++) { 261 cGroup = new ColumnGroup(parent.getStateAt(i)); 262 if (!firstNode) { 263 for (int j = 0; j < nPreviousParentStates; j++) { 264 ColumnGroup group = previousCGroupList.get(columnIndex-1); 265 cGroup.add(group); 266 columnIndex++; 267 } 268 } else { 269 for (int j = 0; j < sizeColumn; j++) { 270 cGroup.add(cModel.getColumn(columnIndex++)); 271 } 272 } 273 cGroupList.add(cGroup); 274 } 275 } 276 previousCGroupList = cGroupList; 277 cGroupList = new ArrayList<ColumnGroup>(); 278 firstNode = false; 279 // Update the number of states 280 nStates /= nPreviousParentStates; 281 } 282 // It adds all parents' node name as header 283 if (cNodeGroup != null) { 284 cModel.addColumnGroup(cNodeGroup); 285 } 286 // It adds only the first row (here it is the last parent's states) 287 // of the header that has all other headers (all other parent's states) 288 // as sub-headers. 289 if (previousCGroupList != null) { 290 for (ColumnGroup group : previousCGroupList) { 291 cModel.addColumnGroup(group); 292 } 293 } 294 table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); 295 296 return table; 297 } 298 299 /** 300 * Show the potential table. Used for DEBUG. 301 * 302 * @param title Title of the window to be shown. 303 */ 304 public void showTable(String title) { 305 JDialog diag = new JDialog(); 306 diag.getContentPane().add(new JScrollPane(makeTable())); 307 diag.pack(); 308 diag.setVisible(true); 309 diag.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); 310 diag.setTitle(title); 311 } 312 313 }