2
|
1 package edu.unc.genomics;
|
|
2
|
|
3 import java.awt.Color;
|
|
4 import java.awt.Component;
|
|
5 import java.awt.Dimension;
|
|
6 import java.awt.FileDialog;
|
|
7 import java.awt.event.ActionEvent;
|
|
8 import java.awt.event.ActionListener;
|
|
9 import java.lang.reflect.Field;
|
|
10 import java.nio.file.Path;
|
|
11 import java.util.HashMap;
|
|
12 import java.util.List;
|
|
13 import java.util.Map;
|
|
14
|
|
15 import javax.swing.BorderFactory;
|
|
16 import javax.swing.BoxLayout;
|
|
17 import javax.swing.ImageIcon;
|
|
18 import javax.swing.JButton;
|
|
19 import javax.swing.JComboBox;
|
|
20 import javax.swing.JComponent;
|
|
21 import javax.swing.JFileChooser;
|
|
22 import javax.swing.JFrame;
|
|
23 import javax.swing.JLabel;
|
|
24 import javax.swing.JPanel;
|
|
25 import javax.swing.JTextField;
|
|
26 import javax.swing.SpringLayout;
|
|
27 import javax.swing.SwingUtilities;
|
|
28 import javax.swing.event.DocumentEvent;
|
|
29 import javax.swing.event.DocumentListener;
|
|
30 import javax.swing.layout.SpringUtilities;
|
|
31 import javax.swing.text.BadLocationException;
|
|
32 import javax.swing.text.Document;
|
|
33
|
|
34 import org.apache.commons.lang3.StringUtils;
|
|
35 import org.apache.log4j.Logger;
|
|
36
|
|
37 import com.beust.jcommander.ParameterDescription;
|
|
38
|
|
39 import edu.unc.genomics.io.IntervalFile;
|
|
40 import edu.unc.genomics.io.WigFile;
|
|
41
|
|
42 /**
|
|
43 * View for configuring the parameters of a Job
|
|
44 * Implements databinding between a Job object and the various Swing components
|
|
45 * for configuring each parameter
|
|
46 *
|
|
47 * @author timpalpant
|
|
48 *
|
|
49 */
|
|
50 public class JobConfigPanel extends JPanel {
|
|
51
|
|
52 private static final long serialVersionUID = 3336295203155728629L;
|
|
53 private static final Logger log = Logger.getLogger(JobConfigPanel.class);
|
|
54
|
|
55 private static final ImageIcon fileIcon = new ImageIcon(ResourceManager.getImagesDirectory().resolve("folder_page.png").toString());
|
|
56
|
|
57 /**
|
|
58 * Maps parameters in the Job to GUI components (forward data-binding)
|
|
59 */
|
|
60 private Map<ParameterDescription, JComponent> guiMap = new HashMap<>();
|
|
61
|
|
62 /**
|
|
63 * Maps GUI components to parameters in the Job (reverse data-binding)
|
|
64 */
|
|
65 private Map<Component, ParameterDescription> jobMap = new HashMap<>();
|
|
66
|
|
67 /**
|
|
68 * The model for the Job that this panel allows you to configure
|
|
69 */
|
|
70 private Job job;
|
|
71
|
|
72 /**
|
|
73 * Initialize a new ConfigurationPanel with no Job
|
|
74 */
|
|
75 public JobConfigPanel() {
|
|
76 this(null);
|
|
77 }
|
|
78
|
|
79 /**
|
|
80 * Initialize a new ConfigurationPanel for the given Job
|
|
81 * @param job
|
|
82 */
|
|
83 public JobConfigPanel(final Job job) {
|
|
84 setJob(job);
|
|
85 setLayout(new SpringLayout());
|
|
86 }
|
|
87
|
|
88 /**
|
|
89 * Return the Job that this ConfigurationPanel is editing
|
|
90 * @return
|
|
91 */
|
|
92 public Job getJob() {
|
|
93 return job;
|
|
94 }
|
|
95
|
|
96 /**
|
|
97 * Set the job for this Configuration panel and re-render
|
|
98 * @param job
|
|
99 */
|
|
100 public void setJob(final Job job) {
|
|
101 this.job = job;
|
|
102 renderJob();
|
|
103 }
|
|
104
|
|
105 /**
|
|
106 * Highlights fields on the Panel that are not set correctly
|
|
107 */
|
|
108 public void highlightInvalidArguments() {
|
|
109 for (ParameterDescription param : job) {
|
|
110 JComponent guiComponent = guiMap.get(param);
|
|
111 if (param.getParameter().required() && !job.isSet(param)) {
|
|
112 guiComponent.setBorder(BorderFactory.createLineBorder(Color.RED));
|
|
113 } else {
|
|
114 guiComponent.setBorder(BorderFactory.createEmptyBorder());
|
|
115 }
|
|
116 }
|
|
117 }
|
|
118
|
|
119 /**
|
|
120 * Render the parameters from the Job into GUI components
|
|
121 * and set up one-way data binding to map changes to the GUI fields
|
|
122 * back into the Job object's parameters
|
|
123 */
|
|
124 private void renderJob() {
|
|
125 removeAll();
|
|
126 guiMap.clear();
|
|
127 jobMap.clear();
|
|
128 if (job == null) {
|
|
129 validate();
|
|
130 repaint();
|
|
131 return;
|
|
132 }
|
|
133
|
|
134 // Iterate through the parameters in the Job
|
|
135 // and render them appropriately based on their type
|
|
136 for (ParameterDescription paramDescription : job) {
|
|
137 // Add the parameter name to the configuration panel
|
|
138 String name = paramDescription.getLongestName();
|
|
139 while (name.startsWith("-")) {
|
|
140 name = name.substring(1);
|
|
141 }
|
|
142 name = StringUtils.capitalize(name);
|
|
143 JLabel label = new JLabel(name);
|
|
144 label.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 5));
|
|
145 add(label);
|
|
146
|
|
147 // Add a panel for configuring the parameter
|
|
148 JPanel fieldPanel = new JPanel();
|
|
149 fieldPanel.setLayout(new BoxLayout(fieldPanel, BoxLayout.LINE_AXIS));
|
|
150 add(fieldPanel);
|
|
151 Field field = paramDescription.getField();
|
|
152 Class<?> type = field.getType();
|
|
153 if (type.equals(Assembly.class)) {
|
|
154 List<Assembly> availableAssemblies = AssemblyManager.getAvailableAssemblies();
|
|
155 Assembly[] assemblies = new Assembly[availableAssemblies.size()];
|
|
156 assemblies = availableAssemblies.toArray(assemblies);
|
|
157 final JComboBox<Assembly> cbAssemblyChooser = new JComboBox<Assembly>(assemblies);
|
|
158 cbAssemblyChooser.setPreferredSize(new Dimension(0, 25));
|
|
159 cbAssemblyChooser.setMaximumSize(new Dimension(Integer.MAX_VALUE, cbAssemblyChooser.getPreferredSize().height));
|
|
160 cbAssemblyChooser.setSelectedItem(AssemblyManager.getLastUsed());
|
|
161 cbAssemblyChooser.addActionListener(new ActionListener() {
|
|
162 public void actionPerformed(ActionEvent e) {
|
|
163 log.debug("Auto-databinding changed assembly into Job argument");
|
|
164 Assembly selectedAssembly = (Assembly) cbAssemblyChooser.getSelectedItem();
|
|
165 AssemblyManager.setLastUsed(selectedAssembly);
|
|
166 ParameterDescription param = jobMap.get(cbAssemblyChooser);
|
|
167 job.setArgument(param, selectedAssembly.toString());
|
|
168 }
|
|
169 });
|
|
170 fieldPanel.add(cbAssemblyChooser);
|
|
171 guiMap.put(paramDescription, cbAssemblyChooser);
|
|
172 jobMap.put(cbAssemblyChooser, paramDescription);
|
|
173 } else {
|
|
174 final JTextField textField = new JTextField();
|
|
175 // Set to default parameter, if it exists
|
|
176 if (job.isSet(paramDescription)) {
|
|
177 textField.setText(job.getArgument(paramDescription));
|
|
178 }
|
|
179 textField.setPreferredSize(new Dimension(0, 20));
|
|
180 textField.setMaximumSize(new Dimension(Integer.MAX_VALUE, textField.getPreferredSize().height));
|
|
181 textField.getDocument().addDocumentListener(new DocumentListener() {
|
|
182 public void changedUpdate(DocumentEvent e) {
|
|
183 pushTextToModel(e);
|
|
184 }
|
|
185
|
|
186 public void removeUpdate(DocumentEvent e) {
|
|
187 pushTextToModel(e);
|
|
188 }
|
|
189
|
|
190 public void insertUpdate(DocumentEvent e) {
|
|
191 pushTextToModel(e);
|
|
192 }
|
|
193
|
|
194 private void pushTextToModel(DocumentEvent e) {
|
|
195 log.debug("Auto-databinding changed text into Job argument");
|
|
196 Document doc = (Document) e.getDocument();
|
|
197 ParameterDescription param = jobMap.get(textField);
|
|
198 try {
|
|
199 String text = doc.getText(0, doc.getLength());
|
|
200 job.setArgument(param, text);
|
|
201 } catch (BadLocationException e1) {
|
|
202 log.error("Error pushing changed text into Job model");
|
|
203 e1.printStackTrace();
|
|
204 }
|
|
205 }
|
|
206 });
|
|
207 fieldPanel.add(textField);
|
|
208 guiMap.put(paramDescription, textField);
|
|
209 jobMap.put(textField, paramDescription);
|
|
210
|
|
211 // For input/output files, add a file chooser button
|
|
212 if (type.equals(Path.class) || type.equals(WigFile.class) || type.equals(IntervalFile.class)) {
|
|
213 // TODO Replace with file icon
|
|
214 JButton btnChooseFile = new JButton(fileIcon);
|
|
215 btnChooseFile.addActionListener(new ActionListener() {
|
|
216 public void actionPerformed(ActionEvent e) {
|
|
217 // AWT FileDialog uses native components, but seems to hang
|
|
218 //Component c = (Component) e.getSource();
|
|
219 //JFrame frame = (JFrame) SwingUtilities.getRoot(c);
|
|
220 //FileDialog fd = new FileDialog(frame, "Choose File");
|
|
221 //fd.setVisible(true);
|
|
222 //if (fd.getFile() != null) {
|
|
223 // textField.setText(fd.getDirectory()+fd.getFile());
|
|
224 //}
|
|
225
|
|
226 // Swing JFileChooser
|
|
227 JFileChooser fc = new JFileChooser();
|
|
228 int retValue = fc.showDialog(getParent(), "OK");
|
|
229 if (retValue == JFileChooser.APPROVE_OPTION) {
|
|
230 textField.setText(fc.getSelectedFile().toString());
|
|
231 }
|
|
232 }
|
|
233 });
|
|
234 fieldPanel.add(btnChooseFile);
|
|
235 }
|
|
236 }
|
|
237 }
|
|
238
|
|
239 // Lay out the panel
|
|
240 SpringUtilities.makeCompactGrid(this, job.numParameters(), 2, 5, 5, 5, 5);
|
|
241
|
|
242 validate();
|
|
243 repaint();
|
|
244 }
|
|
245
|
|
246 }
|