View Javadoc

1   /*
2    * Copyright 2006 - 2012 Christina Bohk and Roland Ewald
3    *  
4    * Licensed under the Apache License, Version 2.0 (the "License"); 
5    * you may not use this file except in compliance with the License. 
6    * You may obtain a copy of the License at 
7    *  
8    *  http://www.apache.org/licenses/LICENSE-2.0
9    *  
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
13   * See the License for the specific language governing permissions and 
14   * limitations under the License. 
15   */
16  package p3j.gui.panels.projections;
17  
18  import java.awt.event.ActionEvent;
19  import java.awt.event.ActionListener;
20  import java.io.File;
21  import java.util.ArrayList;
22  import java.util.List;
23  
24  import javax.swing.JButton;
25  import javax.swing.JFileChooser;
26  import javax.swing.JPanel;
27  import javax.swing.JTextArea;
28  import javax.swing.JTextField;
29  import javax.swing.filechooser.FileFilter;
30  import javax.swing.tree.TreePath;
31  
32  import org.jamesii.core.util.misc.CSVReader;
33  import org.jamesii.core.util.misc.Files;
34  
35  import p3j.database.DatabaseFactory;
36  import p3j.gui.P3J;
37  import p3j.gui.dialogs.EditMatrixDialog;
38  import p3j.gui.dialogs.MoveAssignmentToSetDialog;
39  import p3j.gui.panels.PropertiesShowPanelFactory;
40  import p3j.gui.panels.matrices.EditMatrixPanel;
41  import p3j.misc.MatrixDimension;
42  import p3j.misc.Misc;
43  import p3j.misc.gui.GUI;
44  import p3j.misc.math.Matrix2D;
45  import p3j.pppm.parameters.ParameterAssignment;
46  import p3j.pppm.sets.Set;
47  import p3j.pppm.sets.SetType;
48  
49  /**
50   * Node that represents a {@link ParameterAssignment}.
51   * 
52   * Created: August 24, 2008
53   * 
54   * @author Christina Bohk
55   * @author Roland Ewald
56   * 
57   */
58  public class ParameterAssignmentNode extends
59      ProjectionTreeNode<ParameterAssignment> {
60  
61  	/** Serialization ID. */
62  	private static final long serialVersionUID = -2859181977807670287L;
63  
64  	/** Simple singleton to remember file import directory at runtime. */
65  	private static File importDirectory;
66  
67  	/**
68  	 * Default constructor.
69  	 * 
70  	 * @param assignment
71  	 *          the parameter assignment to be represented
72  	 */
73  	public ParameterAssignmentNode(ParameterAssignment assignment) {
74  		super(assignment, assignment.toString());
75  	}
76  
77  	@Override
78  	protected void refreshRepresentation() {
79  		setUserObject(getEntity().toString());
80  	}
81  
82  	@Override
83  	public JPanel selected(final TreePath selectionPath,
84  	    final IProjectionTree projTree) {
85  
86  		final JTextField name = new JTextField(getEntity().getName());
87  		final JTextArea description = new JTextArea(getEntity().getDescription());
88  		final JTextField probability = new JTextField(getEntity().getProbability()
89  		    + "");
90  		final JTextField deviation = new JTextField(getEntity().getDeviation() + "");
91  		final EditMatrixPanel previewPanel = new EditMatrixPanel(getEntity());
92  
93  		final ParameterAssignmentNode node = this;
94  
95  		// Apply changes
96  		JButton applyButton = new JButton("Apply");
97  		applyButton.addActionListener(new ActionListener() {
98  			@Override
99  			public void actionPerformed(ActionEvent e) {
100 				ParameterAssignment assignment = getEntity();
101 				assignment.setName(name.getText());
102 				assignment.setDescription(description.getText());
103 				assignment.setProbability(Double.parseDouble(probability.getText()));
104 				assignment.setDeviation(Double.parseDouble(deviation.getText()));
105 				setUserObject(assignment.toString());
106 				DatabaseFactory.getDatabaseSingleton().saveParameterAssignment(
107 				    assignment);
108 				projTree.refreshNode(node);
109 			}
110 		});
111 
112 		// Edit matrix
113 		JButton editButton = new JButton("Edit Matrix");
114 		editButton.addActionListener(new ActionListener() {
115 			@Override
116 			public void actionPerformed(ActionEvent e) {
117 				EditMatrixDialog dialog = new EditMatrixDialog(P3J.getInstance(),
118 				    getEntity());
119 				// Avoid displaying plot in preview when new window is opened, as it
120 				// will not be refreshed
121 				previewPanel.setSelectedIndex(0);
122 				dialog.setVisible(true);
123 				getContentPanel().repaint();
124 			}
125 		});
126 
127 		// Import data from file
128 		JButton importButton = new JButton("Import from File");
129 		importButton.addActionListener(new ActionListener() {
130 			@Override
131 			public void actionPerformed(ActionEvent e) {
132 				importDataFromFile();
133 			}
134 		});
135 
136 		// Remove parameter assignment
137 		JButton removeButton = new JButton("Remove");
138 		removeButton.addActionListener(new ActionListener() {
139 			@Override
140 			public void actionPerformed(ActionEvent e) {
141 				if (!GUI.printQuestion(P3J.getInstance(), "Remove '"
142 				    + getEntity().getName() + "'?",
143 				    "Do you really want to remove assignment '" + getEntity().getName()
144 				        + "'? This removal cannot be undone!")) {
145 					return;
146 				}
147 				Set mySet = getProjectionEntity(Set.class);
148 				mySet.removeParameterAssignment(getEntity());
149 				DatabaseFactory.getDatabaseSingleton().saveSet(mySet);
150 				projTree.removeNode(node);
151 			}
152 		});
153 
154 		// Remove parameter assignment
155 		JButton moveButton = new JButton("Move");
156 		moveButton.setToolTipText("Moves assignment to another set.");
157 		moveButton.addActionListener(new ActionListener() {
158 			@Override
159 			public void actionPerformed(ActionEvent e) {
160 				MoveAssignmentToSetDialog mats = new MoveAssignmentToSetDialog(
161 				    getEntity(), projTree, getProjectionEntity(Set.class),
162 				    getProjectionEntity(SetType.class));
163 				if (mats.isMeaningful()) {
164 					mats.setVisible(true);
165 				} else {
166 					GUI.printMessage(P3J.getInstance(), "No other set available",
167 					    "There is no set to move the assignment to. You have to create it first.");
168 				}
169 			}
170 		});
171 
172 		// Layout
173 		List<JButton> buttons = createButtonList(applyButton, editButton,
174 		    importButton, removeButton, moveButton);
175 
176 		PropertiesShowPanelFactory pspf = createPanel(name, description,
177 		    probability, deviation, previewPanel, buttons);
178 
179 		return pspf.constructPanel();
180 	}
181 
182 	/**
183 	 * Creates the button list.
184 	 * 
185 	 * @param addButtons
186 	 *          the buttons to be added
187 	 * 
188 	 * @return the list of buttons
189 	 */
190 	private List<JButton> createButtonList(JButton... addButtons) {
191 		List<JButton> buttons = new ArrayList<JButton>();
192 		for (JButton b : addButtons) {
193 			buttons.add(b);
194 		}
195 		return buttons;
196 	}
197 
198 	/**
199 	 * Creates the panel.
200 	 * 
201 	 * @param name
202 	 *          the name field
203 	 * @param description
204 	 *          the description field
205 	 * @param probability
206 	 *          the probability field
207 	 * @param deviation
208 	 *          the deviation field
209 	 * @param previewPanel
210 	 *          the preview panel
211 	 * @param buttons
212 	 *          the list of buttons
213 	 * 
214 	 * @return the properties show panel factory
215 	 */
216 	private PropertiesShowPanelFactory createPanel(final JTextField name,
217 	    final JTextArea description, final JTextField probability,
218 	    final JTextField deviation, final EditMatrixPanel previewPanel,
219 	    List<JButton> buttons) {
220 		PropertiesShowPanelFactory pspf = new PropertiesShowPanelFactory(buttons, 2);
221 		pspf.sep("General Information");
222 		pspf.app(Misc.GUI_LABEL_NAME, name);
223 		pspf.app(Misc.GUI_LABEL_DESCRIPTION, description, 2);
224 		pspf.app(Misc.GUI_LABEL_PROBABILITY, probability);
225 		if (getEntity().getParamInstance().getValueWidth() == MatrixDimension.YEARS) {
226 			pspf.app(Misc.GUI_LABEL_DEVIATION, deviation);
227 		}
228 		pspf.appPreview(previewPanel);
229 		return pspf;
230 	}
231 
232 	/**
233 	 * Queries user which file to import.
234 	 */
235 	protected void importDataFromFile() {
236 		JFileChooser fileChooser = new JFileChooser(importDirectory);
237 		fileChooser.setFileFilter(new FileFilter() {
238 			@Override
239 			public boolean accept(File f) {
240 				if (f.isDirectory()) {
241 					return true;
242 				}
243 				String ending = Files.getFileEnding(f).toLowerCase();
244 				return (ending.equals("txt") || ending.equals("csv") || ending
245 				    .equals("dat"));
246 			}
247 
248 			@Override
249 			public String getDescription() {
250 				return "(*.csv,*.txt,*.dat) - Text Files containing numeric data as CSV";
251 			}
252 		});
253 
254 		if (JFileChooser.APPROVE_OPTION == fileChooser.showOpenDialog(P3J
255 		    .getInstance())) {
256 			File selection = fileChooser.getSelectedFile();
257 			importDirectory = selection.getParentFile();
258 			readDataFromFile(selection);
259 			getContentPanel().repaint();
260 		}
261 	}
262 
263 	/**
264 	 * Reads data from given file and stores it within the matrix.
265 	 * 
266 	 * @param dataFile
267 	 *          the file containing the data
268 	 */
269 	private void readDataFromFile(File dataFile) {
270 
271 		List<String[]> data = new CSVReader().read(dataFile.getAbsolutePath(),
272 		    false);
273 		Matrix2D value = getEntity().getMatrixValue();
274 		checkForRowMatch(data, value);
275 
276 		boolean errorWasPrinted = false;
277 
278 		for (int i = 0; i < Math.min(value.rows(), data.size()); i++) {
279 			String[] row = data.get(i);
280 			if (!errorWasPrinted) {
281 				errorWasPrinted = checkForColumnMatch(value, i, row);
282 			}
283 			double[] rowData = convertFromString(row);
284 			for (int j = 0; j < Math.min(value.columns(), rowData.length); j++) {
285 				value.setQuick(i, j, rowData[j]);
286 			}
287 		}
288 	}
289 
290 	private double[] convertFromString(String[] row) {
291 		double[] result = new double[row.length];
292 		for (int i = 0; i < row.length; i++) {
293 			try {
294 				result[i] = Double.parseDouble(row[i]);
295 			} catch (NumberFormatException ex) {
296 				GUI.printErrorMessage(P3J.getInstance(), "Number format unknown",
297 				    "The file contains the value '" + row[i]
298 				        + "', which cannot be converted into a number.", ex);
299 			}
300 		}
301 		return result;
302 	}
303 
304 	private void checkForRowMatch(List<String[]> data, Matrix2D value) {
305 		if (value.rows() != data.size()) {
306 			GUI.printErrorMessage(P3J.getInstance(), "Row number does not match",
307 			    "File has " + data.size() + " rows but matrix has " + value.rows()
308 			        + " - importing as much as possible.");
309 		}
310 	}
311 
312 	private boolean checkForColumnMatch(Matrix2D value, int i, String[] row) {
313 		if (row.length == value.columns()) {
314 			return false;
315 		}
316 		GUI.printErrorMessage(
317 		    P3J.getInstance(),
318 		    "Column number does not match",
319 		    "In line"
320 		        + (i + 1)
321 		        + " the file contains "
322 		        + row.length
323 		        + " columns, but there are "
324 		        + value.columns()
325 		        + " matrix columns. Importing as much as possible and ignoring subsequent dimension mismatch.");
326 		return true;
327 	}
328 
329 	@Override
330 	public void deselected() {
331 		super.deselected();
332 		// Save assignment (in case values have been changed)
333 		DatabaseFactory.getDatabaseSingleton().saveParameterAssignment(getEntity());
334 	}
335 
336 }