View Javadoc

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 }