View Javadoc
1   package ca.uhn.hl7v2.testpanel.ui.conf;
2   
3   import java.awt.BorderLayout;
4   import java.awt.CardLayout;
5   import java.awt.Color;
6   import java.awt.Component;
7   import java.awt.Dimension;
8   import java.awt.EventQueue;
9   import java.awt.GridBagConstraints;
10  import java.awt.GridBagLayout;
11  import java.awt.Insets;
12  import java.awt.event.ActionEvent;
13  import java.awt.event.ActionListener;
14  import java.beans.PropertyChangeEvent;
15  import java.beans.PropertyChangeListener;
16  import java.util.ArrayList;
17  import java.util.Collections;
18  import java.util.List;
19  
20  import javax.swing.Box;
21  import javax.swing.DefaultCellEditor;
22  import javax.swing.Icon;
23  import javax.swing.ImageIcon;
24  import javax.swing.JButton;
25  import javax.swing.JComboBox;
26  import javax.swing.JDialog;
27  import javax.swing.JFrame;
28  import javax.swing.JLabel;
29  import javax.swing.JPanel;
30  import javax.swing.JScrollPane;
31  import javax.swing.JTabbedPane;
32  import javax.swing.JTable;
33  import javax.swing.JTextField;
34  import javax.swing.JToolBar;
35  import javax.swing.JTree;
36  import javax.swing.SwingConstants;
37  import javax.swing.event.DocumentEvent;
38  import javax.swing.event.ListSelectionEvent;
39  import javax.swing.event.ListSelectionListener;
40  import javax.swing.event.TreeSelectionEvent;
41  import javax.swing.event.TreeSelectionListener;
42  import javax.swing.table.DefaultTableModel;
43  import javax.swing.tree.AbstractLayoutCache;
44  import javax.swing.tree.DefaultMutableTreeNode;
45  import javax.swing.tree.DefaultTreeModel;
46  import javax.swing.tree.TreeModel;
47  import javax.swing.tree.TreePath;
48  
49  import org.apache.commons.lang.StringUtils;
50  import org.netbeans.swing.outline.DefaultOutlineModel;
51  import org.netbeans.swing.outline.Outline;
52  import org.netbeans.swing.outline.RenderDataProvider;
53  import org.netbeans.swing.outline.RowModel;
54  import org.slf4j.Logger;
55  import org.slf4j.LoggerFactory;
56  
57  import ca.uhn.hl7v2.HL7Exception;
58  import ca.uhn.hl7v2.Version;
59  import ca.uhn.hl7v2.testpanel.controller.ConformanceEditorController;
60  import ca.uhn.hl7v2.testpanel.model.conf.Code;
61  import ca.uhn.hl7v2.testpanel.model.conf.ProfileFileList;
62  import ca.uhn.hl7v2.testpanel.model.conf.ProfileGroup;
63  import ca.uhn.hl7v2.testpanel.model.conf.ProfileGroup.Entry;
64  import ca.uhn.hl7v2.testpanel.model.conf.ProfileProxy;
65  import ca.uhn.hl7v2.testpanel.model.conf.Table;
66  import ca.uhn.hl7v2.testpanel.model.conf.TableFile;
67  import ca.uhn.hl7v2.testpanel.model.conf.TableFileList;
68  import ca.uhn.hl7v2.testpanel.ui.HoverButtonMouseAdapter;
69  import ca.uhn.hl7v2.testpanel.ui.ImageFactory;
70  import ca.uhn.hl7v2.testpanel.util.EventMapUtil;
71  import ca.uhn.hl7v2.testpanel.util.SimpleDocumentListener;
72  
73  public class ConformanceEditorPanel {
74  
75  	public static final String ACK = "ACK";
76  
77  	private static final String CARD_BLANK = "name_1327851037962818000";
78  	private static final String CARD_CODES = "name_1327850619969970000";
79  	private static final String CARD_TABLE_FILE = "name_1327850895484802000";
80  
81  	private static final Logger ourLog = LoggerFactory.getLogger(ConformanceEditorPanel.class);
82  	private JButton myAddProfileButton;
83  	private JButton myAddTableButton;
84  	private JPanel myBlankPanel;
85  	private JButton myCloseFileButton;
86  	private JButton myCloseTableButton;
87  	private JPanel myCodesPanel;
88  	private JTable myCodesTable;
89  	private MyCodesTableModel myCodesTableModel;
90  	private ConformanceEditorController myController;
91  	private JDialog myframe;
92  	private JButton myNewProfileGroupButton;
93  	private Outline myProfilesOutline;
94  	private MyProfilesOutlineModel myProfilesOutlineModel;
95  	private DefaultMutableTreeNode myProfilesOutlineRoot = new DefaultMutableTreeNode();
96  	private MyProfilesTreeModel myProfilesOutlineTreeModel;
97  	private JButton myRemoveProfileButton;
98  	private JButton myRemoveProfileGroupButton;
99  	private boolean myRespondingToChange;
100 	private JPanel myRightCardPanel;
101 	private JTextField myTableFileNameTextF;
102 	private JPanel myTableFilePanel;
103 
104 	private JTree myTableFilesTable;
105 
106 	private DefaultTreeModel myTableFilesTreeModel;
107 
108 	private DefaultMutableTreeNode myTableFilesTreeRoot;
109 
110 	private JTextField myTableIdTextField;
111 
112 	private JTextField myTableNameTextField;
113 
114 	private JButton myRenameButton;
115 
116 	private JButton myExportButton;
117 
118 	/**
119 	 * Create the application.
120 	 * 
121 	 * @param theConformanceEditorController
122 	 */
123 	public ConformanceEditorPanel(ConformanceEditorController theController) {
124 		myController = theController;
125 
126 		initialize();
127 
128 		myController.getTableFileList().addPropertyChangeListener(TableFileList.PROP_FILES, new PropertyChangeListener() {
129 
130 			public void propertyChange(PropertyChangeEvent theEvt) {
131 				updateFileTree(null);
132 			}
133 		});
134 
135 		myController.getProfileFileList().addPropertyChangeListener(ProfileFileList.PROP_FILES, new PropertyChangeListener() {
136 
137 			public void propertyChange(PropertyChangeEvent theEvt) {
138 				updateProfileTree(null);
139 			}
140 
141 		});
142 
143 		updateProfileTree(null);
144 	}
145 
146 	private void addTable() {
147 		Object selectedObject = getSelectedFileOrTable();
148 
149 		TableFile file;
150 		if (selectedObject instanceof TableFile) {
151 			file = (TableFile) selectedObject;
152 		} else if (selectedObject instanceof Table) {
153 			file = ((Table) selectedObject).getTableFile();
154 		} else {
155 			ourLog.error("Selected object isn't a table or file: {}", selectedObject);
156 			return;
157 		}
158 
159 		file = (TableFile) selectedObject;
160 		Table table = file.addTable();
161 
162 		myController.markFileForSaving(file);
163 
164 		updateFileTree(table);
165 
166 	}
167 
168 	public Component getFrame() {
169 		return myframe;
170 	}
171 
172 	public DefaultMutableTreeNode getNodeForRow(int theRowIndex) {
173 		final AbstractLayoutCache layout = myProfilesOutlineModel.getLayout();
174 		TreePath selectionPath = layout.getPathForRow(theRowIndex);
175 		DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode) selectionPath.getLastPathComponent();
176 		return selectedNode;
177 	}
178 
179 	private Object getSelectedFileOrTable() {
180 		TreePath selectionPath = myTableFilesTable.getSelectionPath();
181 		Object selectedObject;
182 		if (selectionPath == null) {
183 			selectedObject = null;
184 		} else {
185 			DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode) selectionPath.getLastPathComponent();
186 			if (selectedNode == null) {
187 				selectedObject = null;
188 			} else {
189 				selectedObject = selectedNode.getUserObject();
190 			}
191 		}
192 		return selectedObject;
193 	}
194 
195 	private Object getSelectedProfileGroupOrFile() {
196 		int selIndex = myProfilesOutline.getSelectionModel().getLeadSelectionIndex();
197 		if (selIndex == -1) {
198 			return null;
199 		}
200 
201 		final AbstractLayoutCache layout = myProfilesOutlineModel.getLayout();
202 		TreePath selectionPath = layout.getPathForRow(selIndex);
203 		Object selectedObject;
204 		if (selectionPath == null) {
205 			selectedObject = null;
206 		} else {
207 			DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode) selectionPath.getLastPathComponent();
208 			if (selectedNode == null) {
209 				selectedObject = null;
210 			} else {
211 				selectedObject = selectedNode.getUserObject();
212 			}
213 		}
214 		return selectedObject;
215 	}
216 
217 	/**
218 	 * Initialize the contents of the frame.
219 	 */
220 	private void initialize() {
221 		myframe = new JDialog();
222 		myframe.setBounds(100, 100, 726, 571);
223 		myframe.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
224 		myTableFilesTreeRoot = new DefaultMutableTreeNode();
225 		myTableFilesTreeModel = new DefaultTreeModel(myTableFilesTreeRoot);
226 		myCodesTableModel = new MyCodesTableModel();
227 
228 		JTabbedPane tabbedPane = new JTabbedPane(JTabbedPane.TOP);
229 		myframe.getContentPane().add(tabbedPane, BorderLayout.CENTER);
230 
231 		JPanel profilesPanel = new JPanel();
232 		tabbedPane.addTab("Profiles", null, profilesPanel, null);
233 		profilesPanel.setLayout(new BorderLayout(0, 0));
234 
235 		myProfilesOutlineTreeModel = new MyProfilesTreeModel();
236 		myProfilesOutlineModel = new MyProfilesOutlineModel(myProfilesOutlineTreeModel);
237 
238 		myProfilesOutline = new Outline(myProfilesOutlineModel);
239 		// myProfilesOutline.setFullyEditable(true);
240 		myProfilesOutline.setFillsViewportHeight(true);
241 		myProfilesOutline.setCellSelectionEnabled(false);
242 		myProfilesOutline.setRowSelectionAllowed(false);
243 		myProfilesOutline.setRootVisible(false);
244 		myProfilesOutline.setGridColor(Color.WHITE);
245 		myProfilesOutline.setColumnHidingAllowed(false);
246 		myProfilesOutline.setRenderDataProvider(new MyProfilesOutlinesRenderProvider());
247 		myProfilesOutline.setDefaultEditor(Object.class, new ProfileGroupCellEditor());
248 		myProfilesOutline.setDefaultEditor(String.class, new ProfileGroupCellComboboxEditor());
249 		myProfilesOutline.setDefaultRenderer(String.class, new ProfilesTreeRenderer(this));
250 		myProfilesOutline.getColumnModel().getColumn(1).setPreferredWidth(60);
251 		myProfilesOutline.getColumnModel().getColumn(1).setMinWidth(60);
252 		myProfilesOutline.getColumnModel().getColumn(1).setMaxWidth(60);
253 		myProfilesOutline.getColumnModel().getColumn(2).setPreferredWidth(60);
254 		myProfilesOutline.getColumnModel().getColumn(2).setMinWidth(60);
255 		myProfilesOutline.getColumnModel().getColumn(2).setMaxWidth(60);
256 		myProfilesOutline.getColumnModel().getColumn(3).setPreferredWidth(200);
257 		myProfilesOutline.getColumnModel().getColumn(3).setMinWidth(200);
258 		myProfilesOutline.getColumnModel().getColumn(3).setMaxWidth(200);
259 		myProfilesOutline.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
260 			public void valueChanged(ListSelectionEvent theE) {
261 				updateSelectedProfilesItem();
262 			}
263 		});
264 
265 		JScrollPane scrollPane_2 = new JScrollPane();
266 		scrollPane_2.setViewportView(myProfilesOutline);
267 		profilesPanel.add(scrollPane_2, BorderLayout.CENTER);
268 
269 		JPanel panel_1 = new JPanel();
270 		profilesPanel.add(panel_1, BorderLayout.NORTH);
271 		GridBagLayout gbl_panel_1 = new GridBagLayout();
272 		gbl_panel_1.columnWidths = new int[] { 644, 0 };
273 		gbl_panel_1.rowHeights = new int[] { 48, 24, 0 };
274 		gbl_panel_1.columnWeights = new double[] { 0.0, Double.MIN_VALUE };
275 		gbl_panel_1.rowWeights = new double[] { 0.0, 0.0, Double.MIN_VALUE };
276 		panel_1.setLayout(gbl_panel_1);
277 
278 		JLabel lblNewLabel_1 = new JLabel(
279 				"<html><center>\nConformance profiles are arranged in groups called <b>Profile Groups</b>. Each Profile Group can define different conformance profiles to be used to validate specific message types. You may also optionally define <b>Table Sets</b> (see the tables tab) to validate code values within messages.\n</center></html>");
280 		GridBagConstraints gbc_lblNewLabel_1 = new GridBagConstraints();
281 		gbc_lblNewLabel_1.anchor = GridBagConstraints.NORTH;
282 		gbc_lblNewLabel_1.fill = GridBagConstraints.HORIZONTAL;
283 		gbc_lblNewLabel_1.insets = new Insets(0, 0, 10, 0);
284 		gbc_lblNewLabel_1.gridx = 0;
285 		gbc_lblNewLabel_1.gridy = 0;
286 		panel_1.add(lblNewLabel_1, gbc_lblNewLabel_1);
287 
288 		JToolBar profilesToolbar = new JToolBar();
289 		GridBagConstraints gbc_profilesToolbar = new GridBagConstraints();
290 		gbc_profilesToolbar.anchor = GridBagConstraints.NORTH;
291 		gbc_profilesToolbar.fill = GridBagConstraints.HORIZONTAL;
292 		gbc_profilesToolbar.gridx = 0;
293 		gbc_profilesToolbar.gridy = 1;
294 		panel_1.add(profilesToolbar, gbc_profilesToolbar);
295 		profilesToolbar.setFloatable(false);
296 
297 		myNewProfileGroupButton = new JButton("New Profile Group");
298 		myNewProfileGroupButton.setToolTipText("Creates a new profile group (which may contain multiple conformance profiles associated with different message types and table mappings)");
299 		myNewProfileGroupButton.setBorderPainted(false);
300 		myNewProfileGroupButton.setIcon(new ImageIcon(ConformanceEditorPanel.class.getResource("/ca/uhn/hl7v2/testpanel/images/new_tree.png")));
301 		myNewProfileGroupButton.addMouseListener(new HoverButtonMouseAdapter(myNewProfileGroupButton));
302 		myNewProfileGroupButton.addActionListener(new ActionListener() {
303 			public void actionPerformed(ActionEvent theE) {
304 				newProfileGroup();
305 			}
306 		});
307 		profilesToolbar.add(myNewProfileGroupButton);
308 
309 		myAddProfileButton = new JButton("Add Profile");
310 		myAddProfileButton.addMouseListener(new HoverButtonMouseAdapter(myAddProfileButton));
311 		myAddProfileButton.setBorderPainted(false);
312 		myAddProfileButton.addActionListener(new ActionListener() {
313 			public void actionPerformed(ActionEvent e) {
314 				Object sel = getSelectedProfileGroupOrFile();
315 				if (sel instanceof ProfileGroup) {
316 					myController.addProfile((ProfileGroup) sel);
317 				} else if (sel instanceof ProfileGroup.Entry) {
318 					myController.addProfile(((ProfileGroup.Entry) sel).getParentProfileGroup());
319 				}
320 			}
321 		});
322 
323 		myRemoveProfileGroupButton = new JButton("Remove");
324 		myRemoveProfileGroupButton.setToolTipText("Close the selected profile group");
325 		myRemoveProfileGroupButton.addActionListener(new ActionListener() {
326 			public void actionPerformed(ActionEvent e) {
327 				ProfileGroup sel = (ProfileGroup) getSelectedProfileGroupOrFile();
328 				myController.closeProfileGroup(sel);
329 			}
330 		});
331 
332 		myRenameButton = new JButton("Rename");
333 		myRenameButton.setToolTipText("Rename the selected profile group");
334 		myRenameButton.addMouseListener(new HoverButtonMouseAdapter(myRenameButton));
335 		myRenameButton.setBorderPainted(false);
336 		myRenameButton.addActionListener(new ActionListener() {
337 			public void actionPerformed(ActionEvent e) {
338 				ProfileGroup sel = (ProfileGroup) getSelectedProfileGroupOrFile();
339 				myController.renameProfileGroup(sel);
340 			}
341 		});
342 		myRenameButton.setIcon(new ImageIcon(ConformanceEditorPanel.class.getResource("/ca/uhn/hl7v2/testpanel/images/rename.png")));
343 		profilesToolbar.add(myRenameButton);
344 		myRemoveProfileGroupButton.setBorderPainted(false);
345 		myRemoveProfileGroupButton.setIcon(new ImageIcon(ConformanceEditorPanel.class.getResource("/ca/uhn/hl7v2/testpanel/images/delete.png")));
346 		myRemoveProfileGroupButton.addMouseListener(new HoverButtonMouseAdapter(myRemoveProfileGroupButton));
347 		profilesToolbar.add(myRemoveProfileGroupButton);
348 		
349 		myExportButton = new JButton("Export");
350 		myExportButton.setToolTipText("Export the selected profile group to a single file that may be shared with other people");
351 		myExportButton.addActionListener(new ActionListener() {
352 			public void actionPerformed(ActionEvent e) {
353 				myController.exportProfileGroup((ProfileGroup)getSelectedProfileGroupOrFile());
354 			}
355 		});
356 		myExportButton.setIcon(new ImageIcon(ConformanceEditorPanel.class.getResource("/ca/uhn/hl7v2/testpanel/images/save_all.png")));
357 		myExportButton.setBorderPainted(false);
358 		myExportButton.addMouseListener(new HoverButtonMouseAdapter(myExportButton));
359 		profilesToolbar.add(myExportButton);
360 		
361 		JButton btnImport = new JButton("Import");
362 		btnImport.setToolTipText("Import a profile group");
363 		btnImport.addMouseListener(new HoverButtonMouseAdapter(btnImport));
364 		btnImport.setBorderPainted(false);
365 		btnImport.setIcon(new ImageIcon(ConformanceEditorPanel.class.getResource("/ca/uhn/hl7v2/testpanel/images/open.png")));
366 		btnImport.addActionListener(new ActionListener() {
367 			public void actionPerformed(ActionEvent theE) {
368 				myController.importProfileGroup();
369 			}
370 		});
371 		profilesToolbar.add(btnImport);
372 		myAddProfileButton.setIcon(new ImageIcon(ConformanceEditorPanel.class.getResource("/ca/uhn/hl7v2/testpanel/images/profile.png")));
373 		profilesToolbar.add(myAddProfileButton);
374 
375 		myRemoveProfileButton = new JButton("Remove Profile");
376 		myRemoveProfileButton.addActionListener(new ActionListener() {
377 			public void actionPerformed(ActionEvent e) {
378 				ProfileGroup.Entry sel = (Entry) getSelectedProfileGroupOrFile();
379 				sel.getParentProfileGroup().removeEntry(sel);
380 			}
381 		});
382 		myRemoveProfileButton.setIcon(new ImageIcon(ConformanceEditorPanel.class.getResource("/ca/uhn/hl7v2/testpanel/images/close.png")));
383 		myRemoveProfileButton.setBorderPainted(false);
384 		myRemoveProfileButton.addMouseListener(new HoverButtonMouseAdapter(myRemoveProfileButton));
385 		profilesToolbar.add(myRemoveProfileButton);
386 
387 		JPanel tablesPanel = new JPanel();
388 		tabbedPane.addTab("Tables", null, tablesPanel, null);
389 		GridBagLayout gbl_tablesPanel = new GridBagLayout();
390 		gbl_tablesPanel.columnWidths = new int[] { 0, 0, 0, 0 };
391 		gbl_tablesPanel.rowHeights = new int[] { 0, 0, 0, 0, 0 };
392 		gbl_tablesPanel.columnWeights = new double[] { 1.0, 0.0, 1.0, Double.MIN_VALUE };
393 		gbl_tablesPanel.rowWeights = new double[] { 0.0, 0.0, 0.0, 1.0, Double.MIN_VALUE };
394 		tablesPanel.setLayout(gbl_tablesPanel);
395 
396 		Component horizontalStrut = Box.createHorizontalStrut(20);
397 		GridBagConstraints gbc_horizontalStrut = new GridBagConstraints();
398 		gbc_horizontalStrut.insets = new Insets(0, 0, 5, 5);
399 		gbc_horizontalStrut.gridx = 1;
400 		gbc_horizontalStrut.gridy = 0;
401 		tablesPanel.add(horizontalStrut, gbc_horizontalStrut);
402 
403 		JToolBar toolBar = new JToolBar();
404 		toolBar.setAlignmentX(Component.LEFT_ALIGNMENT);
405 		toolBar.setFloatable(false);
406 		GridBagConstraints gbc_toolBar = new GridBagConstraints();
407 		gbc_toolBar.anchor = GridBagConstraints.WEST;
408 		gbc_toolBar.insets = new Insets(0, 0, 5, 5);
409 		gbc_toolBar.gridx = 0;
410 		gbc_toolBar.gridy = 1;
411 		tablesPanel.add(toolBar, gbc_toolBar);
412 
413 		JButton btnAddTableFile = new JButton("Add File");
414 		btnAddTableFile.addActionListener(new ActionListener() {
415 			public void actionPerformed(ActionEvent e) {
416 				myController.addTableFile();
417 			}
418 		});
419 		btnAddTableFile.setToolTipText("New Table File...");
420 		btnAddTableFile.setBorderPainted(false);
421 		btnAddTableFile.setIcon(new ImageIcon(ConformanceEditorPanel.class.getResource("/ca/uhn/hl7v2/testpanel/images/file.png")));
422 		btnAddTableFile.addMouseListener(new HoverButtonMouseAdapter(btnAddTableFile));
423 		toolBar.add(btnAddTableFile);
424 
425 		myAddTableButton = new JButton("Add Table");
426 		myAddTableButton.addActionListener(new ActionListener() {
427 			public void actionPerformed(ActionEvent e) {
428 				addTable();
429 			}
430 
431 		});
432 
433 		myCloseFileButton = new JButton("Close File");
434 		myCloseFileButton.setIcon(new ImageIcon(ConformanceEditorPanel.class.getResource("/ca/uhn/hl7v2/testpanel/images/close.png")));
435 		myCloseFileButton.addMouseListener(new HoverButtonMouseAdapter(myCloseFileButton));
436 		myCloseFileButton.addActionListener(new ActionListener() {
437 			public void actionPerformed(ActionEvent e) {
438 				Object selectedFileOrTable = getSelectedFileOrTable();
439 				if (selectedFileOrTable instanceof TableFile) {
440 					myController.closeFile((TableFile) selectedFileOrTable);
441 				} else if (selectedFileOrTable instanceof Table) {
442 					myController.closeFile(((Table) selectedFileOrTable).getTableFile());
443 				}
444 			}
445 		});
446 		myCloseFileButton.setBorderPainted(false);
447 		toolBar.add(myCloseFileButton);
448 		
449 		Component horizontalStrut_1 = Box.createHorizontalStrut(20);
450 		horizontalStrut_1.setMaximumSize(new Dimension(100, 32767));
451 		horizontalStrut_1.setPreferredSize(new Dimension(100, 0));
452 		horizontalStrut_1.setMinimumSize(new Dimension(100, 0));
453 		toolBar.add(horizontalStrut_1);
454 
455 		myAddTableButton.setBorderPainted(false);
456 		myAddTableButton.setIcon(new ImageIcon(ConformanceEditorPanel.class.getResource("/ca/uhn/hl7v2/testpanel/images/table.png")));
457 		myAddTableButton.addMouseListener(new HoverButtonMouseAdapter(myAddTableButton));
458 		toolBar.add(myAddTableButton);
459 
460 		myCloseTableButton = new JButton("Remove Table");
461 		myCloseTableButton.setIcon(new ImageIcon(ConformanceEditorPanel.class.getResource("/ca/uhn/hl7v2/testpanel/images/close.png")));
462 		myCloseTableButton.setBorderPainted(false);
463 		myCloseTableButton.addMouseListener(new HoverButtonMouseAdapter(myCloseTableButton));
464 		myCloseTableButton.addActionListener(new ActionListener() {
465 			public void actionPerformed(ActionEvent theE) {
466 				TableFile tableFile;
467 				Object sel = getSelectedFileOrTable();
468 				Table table;
469 				if (sel instanceof Table) {
470 					table = (Table) sel;
471 					tableFile = table.getTableFile();
472 				} else {
473 					return;
474 				}
475 				tableFile.removeTable(table);
476 				myController.markFileForSaving(tableFile);
477 			}
478 		});
479 		toolBar.add(myCloseTableButton);
480 
481 		JScrollPane scrollPane = new JScrollPane();
482 		GridBagConstraints gbc_scrollPane = new GridBagConstraints();
483 		gbc_scrollPane.gridheight = 2;
484 		gbc_scrollPane.insets = new Insets(0, 0, 0, 5);
485 		gbc_scrollPane.fill = GridBagConstraints.BOTH;
486 		gbc_scrollPane.gridx = 0;
487 		gbc_scrollPane.gridy = 2;
488 		tablesPanel.add(scrollPane, gbc_scrollPane);
489 
490 		myTableFilesTable = new JTree();
491 		myTableFilesTable.addTreeSelectionListener(new TreeSelectionListener() {
492 			public void valueChanged(TreeSelectionEvent e) {
493 				updateSelectedCodesItem();
494 			}
495 		});
496 		myTableFilesTable.setCellRenderer(new TableTreeRenderer());
497 		myTableFilesTable.setShowsRootHandles(true);
498 		myTableFilesTable.setRootVisible(false);
499 		myTableFilesTable.setModel(myTableFilesTreeModel);
500 		scrollPane.setViewportView(myTableFilesTable);
501 
502 		JLabel lblNewLabel = new JLabel(
503 				"<html><center>\nA <b>Table</b> contains a list of allowed values which may be used within\na particular field. Any field with a datatype of ID or IS will have an associated table number, and a Table may be used to define values for it. \n<br><br>\nA <b>Table File</b> contains one or more tables, and may be applied to a message to validate the various coded fields within it.\n</center></html>");
504 		GridBagConstraints gbc_lblNewLabel = new GridBagConstraints();
505 		gbc_lblNewLabel.fill = GridBagConstraints.HORIZONTAL;
506 		gbc_lblNewLabel.insets = new Insets(0, 0, 5, 5);
507 		gbc_lblNewLabel.gridx = 0;
508 		gbc_lblNewLabel.gridy = 0;
509 		tablesPanel.add(lblNewLabel, gbc_lblNewLabel);
510 
511 		myRightCardPanel = new JPanel();
512 		GridBagConstraints gbc_RightCardPanel = new GridBagConstraints();
513 		gbc_RightCardPanel.gridheight = 4;
514 		gbc_RightCardPanel.fill = GridBagConstraints.BOTH;
515 		gbc_RightCardPanel.gridx = 2;
516 		gbc_RightCardPanel.gridy = 0;
517 		tablesPanel.add(myRightCardPanel, gbc_RightCardPanel);
518 		myRightCardPanel.setLayout(new CardLayout(0, 0));
519 
520 		myCodesPanel = new JPanel();
521 		myRightCardPanel.add(myCodesPanel, CARD_CODES);
522 		GridBagLayout gbl_CodesPanel = new GridBagLayout();
523 		gbl_CodesPanel.columnWidths = new int[] { 0, 0, 0 };
524 		gbl_CodesPanel.rowHeights = new int[] { 0, 0, 0, 0, 0 };
525 		gbl_CodesPanel.columnWeights = new double[] { 0.0, 1.0, Double.MIN_VALUE };
526 		gbl_CodesPanel.rowWeights = new double[] { 0.0, 0.0, 0.0, 1.0, Double.MIN_VALUE };
527 		myCodesPanel.setLayout(gbl_CodesPanel);
528 
529 		JLabel lblValues = new JLabel("Codes");
530 		GridBagConstraints gbc_lblValues = new GridBagConstraints();
531 		gbc_lblValues.gridwidth = 2;
532 		gbc_lblValues.insets = new Insets(0, 0, 5, 5);
533 		gbc_lblValues.gridx = 0;
534 		gbc_lblValues.gridy = 0;
535 		myCodesPanel.add(lblValues, gbc_lblValues);
536 
537 		JLabel lblTable = new JLabel("Table");
538 		GridBagConstraints gbc_lblTable = new GridBagConstraints();
539 		gbc_lblTable.insets = new Insets(0, 0, 5, 5);
540 		gbc_lblTable.gridx = 0;
541 		gbc_lblTable.gridy = 1;
542 		myCodesPanel.add(lblTable, gbc_lblTable);
543 
544 		myTableIdTextField = new JTextField();
545 		GridBagConstraints gbc_TableIdTextField = new GridBagConstraints();
546 		gbc_TableIdTextField.insets = new Insets(0, 0, 5, 0);
547 		gbc_TableIdTextField.fill = GridBagConstraints.HORIZONTAL;
548 		gbc_TableIdTextField.gridx = 1;
549 		gbc_TableIdTextField.gridy = 1;
550 		myCodesPanel.add(myTableIdTextField, gbc_TableIdTextField);
551 		myTableIdTextField.setColumns(10);
552 		myTableIdTextField.getDocument().addDocumentListener(new SimpleDocumentListener() {
553 			@Override
554 			public void update(DocumentEvent theE) {
555 				if (myRespondingToChange) {
556 					return;
557 				}
558 				if (getSelectedFileOrTable() instanceof Table) {
559 					Table table = (Table) getSelectedFileOrTable();
560 					table.setCodeSystemId(myTableIdTextField.getText());
561 					myController.markFileForSaving(table.getTableFile());
562 				}
563 			}
564 		});
565 
566 		JLabel lblName = new JLabel("Name");
567 		GridBagConstraints gbc_lblName = new GridBagConstraints();
568 		gbc_lblName.insets = new Insets(0, 0, 5, 5);
569 		gbc_lblName.gridx = 0;
570 		gbc_lblName.gridy = 2;
571 		myCodesPanel.add(lblName, gbc_lblName);
572 
573 		myTableNameTextField = new JTextField();
574 		GridBagConstraints gbc_TableNameTextField = new GridBagConstraints();
575 		gbc_TableNameTextField.insets = new Insets(0, 0, 5, 0);
576 		gbc_TableNameTextField.fill = GridBagConstraints.HORIZONTAL;
577 		gbc_TableNameTextField.gridx = 1;
578 		gbc_TableNameTextField.gridy = 2;
579 		myCodesPanel.add(myTableNameTextField, gbc_TableNameTextField);
580 		myTableNameTextField.setColumns(10);
581 		myTableNameTextField.getDocument().addDocumentListener(new SimpleDocumentListener() {
582 			@Override
583 			public void update(DocumentEvent theE) {
584 				if (myRespondingToChange) {
585 					return;
586 				}
587 				if (getSelectedFileOrTable() instanceof Table) {
588 					Table table = (Table) getSelectedFileOrTable();
589 					table.setCodeSystemName(myTableNameTextField.getText());
590 					myController.markFileForSaving(table.getTableFile());
591 				}
592 			}
593 		});
594 
595 		JScrollPane scrollPane_1 = new JScrollPane();
596 		GridBagConstraints gbc_scrollPane_1 = new GridBagConstraints();
597 		gbc_scrollPane_1.fill = GridBagConstraints.BOTH;
598 		gbc_scrollPane_1.gridwidth = 2;
599 		gbc_scrollPane_1.gridx = 0;
600 		gbc_scrollPane_1.gridy = 3;
601 		myCodesPanel.add(scrollPane_1, gbc_scrollPane_1);
602 
603 		myCodesTable = new JTable();
604 		myCodesTable.setGridColor(Color.LIGHT_GRAY);
605 		scrollPane_1.setViewportView(myCodesTable);
606 		myCodesTable.setModel(myCodesTableModel);
607 
608 		myTableFilePanel = new JPanel();
609 		myRightCardPanel.add(myTableFilePanel, CARD_TABLE_FILE);
610 		GridBagLayout gbl_TableFilePanel = new GridBagLayout();
611 		gbl_TableFilePanel.columnWidths = new int[] { 0, 0, 0 };
612 		gbl_TableFilePanel.rowHeights = new int[] { 0, 0, 0 };
613 		gbl_TableFilePanel.columnWeights = new double[] { 0.0, 1.0, Double.MIN_VALUE };
614 		gbl_TableFilePanel.rowWeights = new double[] { 0.0, 0.0, Double.MIN_VALUE };
615 		myTableFilePanel.setLayout(gbl_TableFilePanel);
616 
617 		JLabel lblTable_1 = new JLabel("Table");
618 		lblTable_1.setHorizontalAlignment(SwingConstants.CENTER);
619 		GridBagConstraints gbc_lblTable_1 = new GridBagConstraints();
620 		gbc_lblTable_1.insets = new Insets(0, 0, 5, 0);
621 		gbc_lblTable_1.fill = GridBagConstraints.HORIZONTAL;
622 		gbc_lblTable_1.gridwidth = 2;
623 		gbc_lblTable_1.gridx = 0;
624 		gbc_lblTable_1.gridy = 0;
625 		myTableFilePanel.add(lblTable_1, gbc_lblTable_1);
626 
627 		JLabel lblName_1 = new JLabel("Name");
628 		GridBagConstraints gbc_lblName_1 = new GridBagConstraints();
629 		gbc_lblName_1.anchor = GridBagConstraints.EAST;
630 		gbc_lblName_1.insets = new Insets(0, 0, 0, 5);
631 		gbc_lblName_1.gridx = 0;
632 		gbc_lblName_1.gridy = 1;
633 		myTableFilePanel.add(lblName_1, gbc_lblName_1);
634 
635 		myTableFileNameTextF = new JTextField();
636 		GridBagConstraints gbc_TableFileNameTextF = new GridBagConstraints();
637 		gbc_TableFileNameTextF.fill = GridBagConstraints.HORIZONTAL;
638 		gbc_TableFileNameTextF.gridx = 1;
639 		gbc_TableFileNameTextF.gridy = 1;
640 		myTableFilePanel.add(myTableFileNameTextF, gbc_TableFileNameTextF);
641 		myTableFileNameTextF.setColumns(10);
642 		myTableFileNameTextF.getDocument().addDocumentListener(new SimpleDocumentListener() {
643 			@Override
644 			public void update(DocumentEvent theE) {
645 				if (myRespondingToChange) {
646 					return;
647 				}
648 				if (getSelectedFileOrTable() instanceof TableFile) {
649 					TableFile file = (TableFile) getSelectedFileOrTable();
650 					file.setName(myTableFileNameTextF.getText());
651 					myController.markFileForSaving(file);
652 				}
653 			}
654 		});
655 
656 		myBlankPanel = new JPanel();
657 		myRightCardPanel.add(myBlankPanel, CARD_BLANK);
658 
659 		JPanel controlButtonsPanel = new JPanel();
660 		myframe.getContentPane().add(controlButtonsPanel, BorderLayout.SOUTH);
661 		GridBagLayout gbl_controlButtonsPanel = new GridBagLayout();
662 		gbl_controlButtonsPanel.columnWidths = new int[] { 0, 0, 0, 0 };
663 		gbl_controlButtonsPanel.rowHeights = new int[] { 0, 0 };
664 		gbl_controlButtonsPanel.columnWeights = new double[] { 1.0, 0.0, 0.0, Double.MIN_VALUE };
665 		gbl_controlButtonsPanel.rowWeights = new double[] { 0.0, Double.MIN_VALUE };
666 		controlButtonsPanel.setLayout(gbl_controlButtonsPanel);
667 
668 		JButton saveButton = new JButton("Close");
669 		saveButton.addActionListener(new ActionListener() {
670 			public void actionPerformed(ActionEvent e) {
671 				myframe.setVisible(false);
672 			}
673 		});
674 		GridBagConstraints gbc_saveButton = new GridBagConstraints();
675 		gbc_saveButton.gridx = 2;
676 		gbc_saveButton.gridy = 0;
677 		controlButtonsPanel.add(saveButton, gbc_saveButton);
678 
679 	}
680 
681 	private void newProfileGroup() {
682 		myController.newProfileGroup();
683 	}
684 
685 	public void show() {
686 		myframe.setVisible(true);
687 
688 		updateFileTree(null);
689 		updateSelectedCodesItem();
690 		updateSelectedProfilesItem();
691 	}
692 
693 	private void updateFileTree(Object theSelectedObject) {
694 
695 		List<TableFile> tableFiles = myController.getTableFileList().getTableFiles();
696 		int row = 0;
697 		for (int i = 0; i < tableFiles.size(); i++) {
698 			TableFile nextFile = tableFiles.get(i);
699 
700 			if (myTableFilesTreeRoot.getChildCount() <= i || ((DefaultMutableTreeNode) myTableFilesTreeRoot.getChildAt(i)).getUserObject() != nextFile) {
701 				myTableFilesTreeRoot.insert(new DefaultMutableTreeNode(nextFile), i);
702 				nextFile.addPropertyChangeListener(TableFile.PROP_TABLES, new PropertyChangeListener() {
703 					public void propertyChange(PropertyChangeEvent theEvt) {
704 						updateFileTree(null);
705 					}
706 				});
707 			}
708 
709 			DefaultMutableTreeNode nextNode = (DefaultMutableTreeNode) myTableFilesTreeRoot.getChildAt(i);
710 			if (nextNode.getUserObject() == theSelectedObject) {
711 				myTableFilesTable.expandRow(row);
712 				myTableFilesTable.setSelectionRow(row);
713 			} else {
714 				myTableFilesTable.collapseRow(row);
715 			}
716 
717 			final int parentRow = row;
718 
719 			DefaultMutableTreeNode nextFileNode = (DefaultMutableTreeNode) myTableFilesTreeRoot.getChildAt(i);
720 			for (int j = 0; j < nextFile.getTables().size(); j++) {
721 
722 				Table nextTable = nextFile.getTables().get(j);
723 				if (nextFileNode.getChildCount() <= j || ((DefaultMutableTreeNode) nextFileNode.getChildAt(j)).getUserObject() != nextTable) {
724 					nextFileNode.insert(new DefaultMutableTreeNode(nextTable), j);
725 					nextTable.addPropertyChangeListener(Table.PROP_CODES, new PropertyChangeListener() {
726 
727 						public void propertyChange(PropertyChangeEvent theEvt) {
728 							myTableFilesTable.repaint();
729 						}
730 					});
731 				}
732 
733 				while (nextFileNode.getChildCount() > nextFile.getTables().size()) {
734 					nextFileNode.remove(nextFile.getTables().size());
735 				}
736 
737 				row++;
738 
739 				DefaultMutableTreeNode nextTableNode = (DefaultMutableTreeNode) nextFileNode.getChildAt(j);
740 				if (nextTableNode.getUserObject() == theSelectedObject) {
741 					final int curRow = row;
742 					EventQueue.invokeLater(new Runnable() {
743 						public void run() {
744 							myTableFilesTable.expandRow(parentRow);
745 							myTableFilesTable.setSelectionInterval(curRow, curRow);
746 						}
747 					});
748 				}
749 
750 			}
751 
752 			row++;
753 		}
754 
755 		while (myTableFilesTreeRoot.getChildCount() > tableFiles.size()) {
756 			myTableFilesTreeRoot.remove(tableFiles.size());
757 		}
758 
759 		myTableFilesTreeModel.nodeStructureChanged(myTableFilesTreeRoot);
760 	}
761 
762 	private void updateProfileTree(Object theSelectedObject) {
763 
764 		List<ProfileGroup> profileFiles = myController.getProfileFileList().getProfiles();
765 		int row = 0;
766 		for (int i = 0; i < profileFiles.size(); i++) {
767 			final ProfileGroup nextGroup = profileFiles.get(i);
768 
769 			if (myProfilesOutlineRoot.getChildCount() <= i || ((DefaultMutableTreeNode) myProfilesOutlineRoot.getChildAt(i)).getUserObject() != nextGroup) {
770 				myProfilesOutlineRoot.insert(new ProfileGroupNode(nextGroup), i);
771 				nextGroup.addPropertyChangeListener(ProfileGroup.PROP_PROFILES, new PropertyChangeListener() {
772 					public void propertyChange(PropertyChangeEvent theEvt) {
773 						updateProfileTree(theEvt.getNewValue());
774 					}
775 				});
776 			}
777 
778 			DefaultMutableTreeNode nextNode = (DefaultMutableTreeNode) myProfilesOutlineRoot.getChildAt(i);
779 			final AbstractLayoutCache layout = myProfilesOutlineModel.getLayout();
780 			TreePath path = layout.getPathForRow(row);
781 			if (nextNode.getUserObject() == theSelectedObject) {
782 				myProfilesOutline.expandPath(path);
783 				myProfilesOutline.getSelectionModel().setSelectionInterval(row, row);
784 			} else {
785 				myProfilesOutline.collapsePath(path);
786 			}
787 
788 			final int parentRow = row;
789 
790 			ProfileGroupNode nextFileNode = (ProfileGroupNode) myProfilesOutlineRoot.getChildAt(i);
791 			for (int j = 0; j < nextGroup.getEntries().size(); j++) {
792 
793 				Entry nextEntry = nextGroup.getEntries().get(j);
794 				if (nextFileNode.getChildCount() <= j || ((DefaultMutableTreeNode) nextFileNode.getChildAt(j)).getUserObject() != nextEntry) {
795 					nextFileNode.insert(new ProfileNode(nextEntry), j);
796 					nextEntry.addPropertyChangeListener(ProfileGroup.Entry.PROP_DESC, new PropertyChangeListener() {
797 
798 						public void propertyChange(PropertyChangeEvent theEvt) {
799 							myProfilesOutline.repaint();
800 						}
801 					});
802 				}
803 
804 				row++;
805 
806 				DefaultMutableTreeNode nextTableNode = (DefaultMutableTreeNode) nextFileNode.getChildAt(j);
807 				if (nextTableNode.getUserObject() == theSelectedObject) {
808 					final int curRow = row;
809 					EventQueue.invokeLater(new Runnable() {
810 						public void run() {
811 							TreePath path = layout.getPathForRow(parentRow);
812 							myProfilesOutline.expandPath(path);
813 							myProfilesOutline.getSelectionModel().setSelectionInterval(curRow, curRow);
814 						}
815 					});
816 				}
817 
818 			}
819 
820 			while (nextFileNode.getChildCount() > nextGroup.getEntries().size()) {
821 				nextFileNode.remove(nextGroup.getEntries().size());
822 			}
823 
824 			row++;
825 		}
826 
827 		while (myProfilesOutlineRoot.getChildCount() > profileFiles.size()) {
828 			myProfilesOutlineRoot.remove(profileFiles.size());
829 		}
830 
831 		myProfilesOutlineTreeModel.reload();
832 	}
833 
834 	private void updateSelectedCodesItem() {
835 		myRespondingToChange = true;
836 		CardLayout cl = (CardLayout) (myRightCardPanel.getLayout());
837 
838 		Object selectedItem = getSelectedFileOrTable();
839 		if (selectedItem instanceof Table) {
840 
841 			Table table = (Table) selectedItem;
842 			myTableIdTextField.setText(table.getCodeSystemId());
843 			myTableNameTextField.setText(table.getCodeSystemName());
844 			myCodesTableModel.setTable(table);
845 			myAddTableButton.setEnabled(true);
846 			myCloseFileButton.setEnabled(true);
847 			myCloseTableButton.setEnabled(true);
848 
849 			cl.show(myRightCardPanel, CARD_CODES);
850 
851 		} else if (selectedItem instanceof TableFile) {
852 
853 			TableFile tf = (TableFile) selectedItem;
854 			myTableFileNameTextF.setText(tf.getName());
855 			cl.show(myRightCardPanel, CARD_TABLE_FILE);
856 			myAddTableButton.setEnabled(true);
857 			myCloseFileButton.setEnabled(true);
858 			myCloseTableButton.setEnabled(false);
859 
860 		} else {
861 
862 			cl.show(myRightCardPanel, CARD_BLANK);
863 			myAddTableButton.setEnabled(false);
864 			myCloseFileButton.setEnabled(false);
865 			myCloseTableButton.setEnabled(false);
866 
867 		}
868 
869 		myRespondingToChange = false;
870 	}
871 
872 	private void updateSelectedProfilesItem() {
873 
874 		Object sel = getSelectedProfileGroupOrFile();
875 		if (sel instanceof ProfileGroup) {
876 			myExportButton.setEnabled(true);
877 			myRemoveProfileGroupButton.setEnabled(true);
878 			myRemoveProfileButton.setEnabled(false);
879 			myAddProfileButton.setEnabled(true);
880 			myRenameButton.setEnabled(true);
881 		} else if (sel instanceof ProfileGroup.Entry) {
882 			myExportButton.setEnabled(false);
883 			myRemoveProfileGroupButton.setEnabled(false);
884 			myRemoveProfileButton.setEnabled(true);
885 			myAddProfileButton.setEnabled(true);
886 			myRenameButton.setEnabled(false);
887 		} else {
888 			myExportButton.setEnabled(false);
889 			myRemoveProfileGroupButton.setEnabled(false);
890 			myRemoveProfileButton.setEnabled(false);
891 			myAddProfileButton.setEnabled(false);
892 			myRenameButton.setEnabled(false);
893 		}
894 
895 	}
896 
897 	private class MyCodesTableModel extends DefaultTableModel {
898 
899 		private Table myTable;
900 
901 		public MyCodesTableModel() {
902 			addColumn("Code");
903 			addColumn("Name");
904 		}
905 
906 		@Override
907 		public int getRowCount() {
908 			if (myTable == null) {
909 				return 0;
910 			}
911 			return myTable.getCodes().size() + 1;
912 		}
913 
914 		@Override
915 		public Object getValueAt(int theRow, int theColumn) {
916 			if (myTable.getCodes().size() == theRow) {
917 				return "";
918 			}
919 
920 			Code code = myTable.getCodes().get(theRow);
921 			switch (theColumn) {
922 			case 0:
923 				return code.getCode();
924 			case 1:
925 				return code.getDisplayName();
926 			}
927 
928 			return "";
929 		}
930 
931 		@Override
932 		public boolean isCellEditable(int theRow, int theColumn) {
933 			return true;
934 		}
935 
936 		private void setTable(Table theTable) {
937 			if (myTable != theTable) {
938 				myTable = theTable;
939 				fireTableDataChanged();
940 			}
941 		}
942 
943 		@Override
944 		public void setValueAt(Object theAValue, int theRow, int theColumn) {
945 			Code code;
946 			if (myTable.getCodes().size() == theRow) {
947 				code = new Code();
948 				myTable.addCode(code);
949 			}
950 
951 			code = myTable.getCodes().get(theRow);
952 
953 			switch (theColumn) {
954 			case 0:
955 				code.setCode(theAValue.toString());
956 				break;
957 			case 1:
958 				code.setDisplayName(theAValue.toString());
959 				break;
960 			}
961 
962 			myController.markFileForSaving(myTable.getTableFile());
963 		}
964 
965 	}
966 
967 	public class MyProfilesOutlineModel extends DefaultOutlineModel {
968 
969 		protected MyProfilesOutlineModel(TreeModel theTreeModel) {
970 			super(theTreeModel, new MyProfilesRowModel(), false, "Profiles");
971 		}
972 
973 		@Override
974 		public boolean isCellEditable(int theRowIndex, int theColumnIndex) {
975 			if (theColumnIndex == 0) {
976 				DefaultMutableTreeNode selectedNode = getNodeForRow(theRowIndex);
977 				if (selectedNode instanceof ProfileGroupNode) {
978 					return true;
979 				} else {
980 					return false;
981 				}
982 			}
983 			return super.isCellEditable(theRowIndex, theColumnIndex);
984 		}
985 
986 		@Override
987 		protected void setTreeValueAt(Object theAValue, int theRowIndex) {
988 			DefaultMutableTreeNode selectedNode = getNodeForRow(theRowIndex);
989 			if (selectedNode instanceof ProfileGroupNode) {
990 				((ProfileGroupNode) selectedNode).getUserObject().setName(theAValue.toString());
991 			} else {
992 				ourLog.error("Unknown type {}", selectedNode.getClass());
993 			}
994 
995 			myController.getProfileFileList().updatePrefs();
996 		}
997 	}
998 
999 	private class MyProfilesOutlinesRenderProvider implements RenderDataProvider {
1000 
1001 		public Color getBackground(Object theArg0) {
1002 			return Color.white;
1003 		}
1004 
1005 		public String getDisplayName(Object theArg0) {
1006 			if (theArg0 instanceof ProfileGroupNode) {
1007 				return ((ProfileGroupNode) theArg0).getUserObject().getName();
1008 			}
1009 
1010 			if (theArg0 instanceof ProfileNode) {
1011 				ProfileProxy profileProxy = ((ProfileNode) theArg0).getUserObject().getProfileProxy();
1012 				return profileProxy.getName();
1013 			}
1014 
1015 			return "Unknown";
1016 		}
1017 
1018 		public Color getForeground(Object theArg0) {
1019 			return Color.black;
1020 		}
1021 
1022 		public Icon getIcon(Object theArg0) {
1023 			if (theArg0 instanceof ProfileGroupNode) {
1024 				return ImageFactory.getProfileGroup();
1025 			} else {
1026 				return ImageFactory.getProfile();
1027 			}
1028 		}
1029 
1030 		public String getTooltipText(Object theArg0) {
1031 			return null;
1032 		}
1033 
1034 		public boolean isHtmlDisplayName(Object theArg0) {
1035 			return true;
1036 		}
1037 
1038 	}
1039 
1040 	public class MyProfilesRowModel implements RowModel {
1041 
1042 		public static final int COL_MSG_TYPE = 0;
1043 		public static final int COL_TABLES = 2;
1044 		public static final int COL_TRIGGER = 1;
1045 
1046 		public Class<?> getColumnClass(int theArg0) {
1047 			return String.class;
1048 		}
1049 
1050 		public int getColumnCount() {
1051 			return 3;
1052 		}
1053 
1054 		public String getColumnName(int theArg0) {
1055 			switch (theArg0) {
1056 			case COL_MSG_TYPE:
1057 				return "Msg Type";
1058 			case COL_TRIGGER:
1059 				return "Trigger";
1060 			case COL_TABLES:
1061 				return "Table File";
1062 			}
1063 			return null;
1064 		}
1065 
1066 		public Object getValueFor(Object theNode, int theColumn) {
1067 			if (theNode instanceof ProfileNode) {
1068 				ProfileNode pn = (ProfileNode) theNode;
1069 				switch (theColumn) {
1070 				case COL_MSG_TYPE:
1071 					return pn.getUserObject().getMessageType();
1072 				case COL_TRIGGER:
1073 					return pn.getUserObject().getEventType();
1074 				case COL_TABLES:
1075 					String tableFileId = pn.getUserObject().getTablesId();
1076 					if (tableFileId == null) {
1077 						return null;
1078 					}
1079 					TableFile tableFile = myController.getTableFileList().getTableFile(tableFileId);
1080 					if (tableFile == null) {
1081 						return null;
1082 					}
1083 					return tableFile.getName();
1084 				}
1085 			}
1086 			return null;
1087 		}
1088 
1089 		public boolean isCellEditable(Object theNode, int theColumn) {
1090 			if (theNode instanceof ProfileGroupNode) {
1091 				return false;
1092 			} else if (theNode instanceof ProfileNode) {
1093 				return true;
1094 			} else {
1095 				ourLog.error("Unknown type {}", theNode.getClass());
1096 				return false;
1097 			}
1098 		}
1099 
1100 		public void setValueFor(Object theNode, int theColumn, Object theValue) {
1101 			if (theNode instanceof ProfileNode) {
1102 				ProfileNode pn = (ProfileNode) theNode;
1103 				switch (theColumn) {
1104 				case COL_MSG_TYPE:
1105 					pn.getUserObject().setMessageType(theValue.toString());
1106 					break;
1107 				case COL_TRIGGER:
1108 					pn.getUserObject().setEventType(theValue.toString());
1109 					break;
1110 				case COL_TABLES:
1111 					if (TBL_OPT_NONE.equals(theValue.toString())) {
1112 						pn.getUserObject().setTablesId(null);
1113 					} else if (theValue.toString().contains(":") == false) {
1114 						// the value isn't changing in this case
1115 						return;
1116 					} else {
1117 						String value = theValue.toString().replaceAll(":.*", "");
1118 						int index = Integer.parseInt(value) - 1;
1119 						String tblId = myController.getTableFileList().getTableFiles().get(index).getId();
1120 						pn.getUserObject().setTablesId(tblId);
1121 					}
1122 					break;
1123 				}
1124 
1125 				myController.getProfileFileList().updatePrefs();
1126 
1127 			}
1128 		}
1129 
1130 	}
1131 
1132 	public class MyProfilesTreeModel extends DefaultTreeModel {
1133 
1134 		public MyProfilesTreeModel() {
1135 			super(myProfilesOutlineRoot);
1136 		}
1137 
1138 	}
1139 
1140 	private static final String TBL_OPT_NONE = "None";
1141 
1142 	public class ProfileGroupCellComboboxEditor extends DefaultCellEditor {
1143 
1144 		public ProfileGroupCellComboboxEditor() {
1145 			super(new JComboBox());
1146 		}
1147 
1148 		private List<String> getSortedStructures() {
1149 			ArrayList<String> retVal = new ArrayList<String>();
1150 			try {
1151 				for (String next : EventMapUtil.getEventMap(Version.latestVersion().getVersion()).keySet()) {
1152 					retVal.add(next);
1153 				}
1154 			} catch (HL7Exception e) {
1155 				ourLog.error("Failed to load structures", e);
1156 			}
1157 
1158 			Collections.sort(retVal);
1159 
1160 			return retVal;
1161 		}
1162 
1163 		/*
1164 		 * (non-Javadoc)
1165 		 * 
1166 		 * @see
1167 		 * javax.swing.DefaultCellEditor#getTableCellEditorComponent(javax.swing
1168 		 * .JTable, java.lang.Object, boolean, int, int)
1169 		 */
1170 		@Override
1171 		public Component getTableCellEditorComponent(JTable theTable, Object theValue, boolean theIsSelected, int theRow, int theColumn) {
1172 
1173 			final AbstractLayoutCache layout = myProfilesOutlineModel.getLayout();
1174 			TreePath selectionPath = layout.getPathForRow(theRow);
1175 			ProfileNode selectedNode = (ProfileNode) selectionPath.getLastPathComponent();
1176 
1177 			JComboBox retVal = (JComboBox) super.getTableCellEditorComponent(theTable, theValue, theIsSelected, theRow, theColumn);
1178 			retVal.removeAllItems();
1179 
1180 //			Properties structures = new Properties();
1181 //			try {
1182 //				structures = Parser.getMessageStructures(Version.latestVersion().getVersion());
1183 //			} catch (IOException e) {
1184 //				ourLog.error("Failed to load message types", e);
1185 //			}
1186 
1187 			if (theColumn - 1 == MyProfilesRowModel.COL_MSG_TYPE) {
1188 
1189 				if (!"*".equals(theValue)) {
1190 					retVal.addItem("*");
1191 				}
1192 
1193 				if (!ACK.equals(theValue)) {
1194 					retVal.addItem(ACK);
1195 				}
1196 
1197 				String prevKey = "";
1198 				for (String nextStruct : getSortedStructures()) {
1199 					String[] nextParts = nextStruct.split("_");
1200 					if (StringUtils.isNotBlank(nextParts[0]) && nextParts[0].equals(prevKey) == false) {
1201 						prevKey = nextParts[0];
1202 						retVal.addItem(prevKey);
1203 					}
1204 				}
1205 
1206 				retVal.setSelectedItem(theValue);
1207 
1208 			} else if (theColumn - 1 == MyProfilesRowModel.COL_TRIGGER) {
1209 
1210 				if (!"*".equals(theValue)) {
1211 					retVal.addItem("*");
1212 				}
1213 
1214 				for (String nextStruct : getSortedStructures()) {
1215 					String[] nextParts = nextStruct.split("_");
1216 					String selMsgType = selectedNode.getUserObject().getMessageType();
1217 					if (nextParts.length > 1 && StringUtils.isNotBlank(nextParts[0]) && StringUtils.isNotBlank(nextParts[1]) && (nextParts[0].equals(selMsgType) || "*".equals(selMsgType))) {
1218 						retVal.addItem(nextParts[1]);
1219 					}
1220 				}
1221 
1222 				retVal.setSelectedItem(theValue);
1223 
1224 			} else if (theColumn - 1 == MyProfilesRowModel.COL_TABLES) {
1225 
1226 				retVal.addItem(TBL_OPT_NONE);
1227 				retVal.setSelectedIndex(0);
1228 
1229 				for (int i = 1; i <= myController.getTableFileList().getTableFiles().size(); i++) {
1230 					TableFile tableFile = myController.getTableFileList().getTableFiles().get(i - 1);
1231 					retVal.addItem((i) + ": " + tableFile.getName());
1232 
1233 					if (tableFile.getId().equals(selectedNode.getUserObject().getTablesId())) {
1234 						retVal.setSelectedIndex(i);
1235 					}
1236 
1237 				}
1238 
1239 			}
1240 
1241 			return retVal;
1242 		}
1243 
1244 		/*
1245 		 * (non-Javadoc)
1246 		 * 
1247 		 * @see
1248 		 * javax.swing.DefaultCellEditor#getTreeCellEditorComponent(javax.swing
1249 		 * .JTree, java.lang.Object, boolean, boolean, boolean, int)
1250 		 */
1251 		@Override
1252 		public Component getTreeCellEditorComponent(JTree theTree, Object theValue, boolean theIsSelected, boolean theExpanded, boolean theLeaf, int theRow) {
1253 			return super.getTreeCellEditorComponent(theTree, theValue, theIsSelected, theExpanded, theLeaf, theRow);
1254 		}
1255 
1256 	}
1257 
1258 	private final class ProfileGroupCellEditor extends DefaultCellEditor {
1259 		public ProfileGroupCellEditor() {
1260 			super(new JTextField());
1261 			setClickCountToStart(1);
1262 		}
1263 
1264 		private ProfileGroupCellEditor(JTextField theTextField) {
1265 			super(theTextField);
1266 		}
1267 
1268 		@Override
1269 		public Component getTableCellEditorComponent(JTable theTable, Object theValue, boolean theIsSelected, int theRow, int theColumn) {
1270 			Component retVal = super.getTableCellEditorComponent(theTable, theValue, theIsSelected, theRow, theColumn);
1271 			if (theValue instanceof ProfileGroupNode) {
1272 				ProfileGroupNode value = (ProfileGroupNode) theValue;
1273 				((JTextField) retVal).setText(value.getUserObject().getName());
1274 				// } else {
1275 				// ProfileNode value = (ProfileNode) theValue;
1276 				// ((JTextField)
1277 				// retVal).setText(value.getUserObject().getName());
1278 			}
1279 			return retVal;
1280 		}
1281 
1282 		@Override
1283 		public Component getTreeCellEditorComponent(JTree theTree, Object theValue, boolean theIsSelected, boolean theExpanded, boolean theLeaf, int theRow) {
1284 			Component retVal = super.getTreeCellEditorComponent(theTree, theValue, theIsSelected, theExpanded, theLeaf, theRow);
1285 			return retVal;
1286 		}
1287 	}
1288 
1289 	public class ProfileGroupNode extends DefaultMutableTreeNode {
1290 		public ProfileGroupNode(ProfileGroup theProfileGroup) {
1291 			super(theProfileGroup);
1292 		}
1293 
1294 		@Override
1295 		public ProfileGroup getUserObject() {
1296 			return (ProfileGroup) super.getUserObject();
1297 		}
1298 	}
1299 
1300 	public class ProfileNode extends DefaultMutableTreeNode {
1301 		public ProfileNode(ProfileGroup.Entry theProfile) {
1302 			super(theProfile);
1303 		}
1304 
1305 		@Override
1306 		public ProfileGroup.Entry getUserObject() {
1307 			return (ProfileGroup.Entry) super.getUserObject();
1308 		}
1309 	}
1310 
1311 }