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 			@Override
368 			public void actionPerformed(ActionEvent theE) {
369 				myController.importProfileGroup();
370 			}
371 		});
372 		profilesToolbar.add(btnImport);
373 		myAddProfileButton.setIcon(new ImageIcon(ConformanceEditorPanel.class.getResource("/ca/uhn/hl7v2/testpanel/images/profile.png")));
374 		profilesToolbar.add(myAddProfileButton);
375 
376 		myRemoveProfileButton = new JButton("Remove Profile");
377 		myRemoveProfileButton.addActionListener(new ActionListener() {
378 			public void actionPerformed(ActionEvent e) {
379 				ProfileGroup.Entry sel = (Entry) getSelectedProfileGroupOrFile();
380 				sel.getParentProfileGroup().removeEntry(sel);
381 			}
382 		});
383 		myRemoveProfileButton.setIcon(new ImageIcon(ConformanceEditorPanel.class.getResource("/ca/uhn/hl7v2/testpanel/images/close.png")));
384 		myRemoveProfileButton.setBorderPainted(false);
385 		myRemoveProfileButton.addMouseListener(new HoverButtonMouseAdapter(myRemoveProfileButton));
386 		profilesToolbar.add(myRemoveProfileButton);
387 
388 		JPanel tablesPanel = new JPanel();
389 		tabbedPane.addTab("Tables", null, tablesPanel, null);
390 		GridBagLayout gbl_tablesPanel = new GridBagLayout();
391 		gbl_tablesPanel.columnWidths = new int[] { 0, 0, 0, 0 };
392 		gbl_tablesPanel.rowHeights = new int[] { 0, 0, 0, 0, 0 };
393 		gbl_tablesPanel.columnWeights = new double[] { 1.0, 0.0, 1.0, Double.MIN_VALUE };
394 		gbl_tablesPanel.rowWeights = new double[] { 0.0, 0.0, 0.0, 1.0, Double.MIN_VALUE };
395 		tablesPanel.setLayout(gbl_tablesPanel);
396 
397 		Component horizontalStrut = Box.createHorizontalStrut(20);
398 		GridBagConstraints gbc_horizontalStrut = new GridBagConstraints();
399 		gbc_horizontalStrut.insets = new Insets(0, 0, 5, 5);
400 		gbc_horizontalStrut.gridx = 1;
401 		gbc_horizontalStrut.gridy = 0;
402 		tablesPanel.add(horizontalStrut, gbc_horizontalStrut);
403 
404 		JToolBar toolBar = new JToolBar();
405 		toolBar.setAlignmentX(Component.LEFT_ALIGNMENT);
406 		toolBar.setFloatable(false);
407 		GridBagConstraints gbc_toolBar = new GridBagConstraints();
408 		gbc_toolBar.anchor = GridBagConstraints.WEST;
409 		gbc_toolBar.insets = new Insets(0, 0, 5, 5);
410 		gbc_toolBar.gridx = 0;
411 		gbc_toolBar.gridy = 1;
412 		tablesPanel.add(toolBar, gbc_toolBar);
413 
414 		JButton btnAddTableFile = new JButton("Add File");
415 		btnAddTableFile.addActionListener(new ActionListener() {
416 			public void actionPerformed(ActionEvent e) {
417 				myController.addTableFile();
418 			}
419 		});
420 		btnAddTableFile.setToolTipText("New Table File...");
421 		btnAddTableFile.setBorderPainted(false);
422 		btnAddTableFile.setIcon(new ImageIcon(ConformanceEditorPanel.class.getResource("/ca/uhn/hl7v2/testpanel/images/file.png")));
423 		btnAddTableFile.addMouseListener(new HoverButtonMouseAdapter(btnAddTableFile));
424 		toolBar.add(btnAddTableFile);
425 
426 		myAddTableButton = new JButton("Add Table");
427 		myAddTableButton.addActionListener(new ActionListener() {
428 			public void actionPerformed(ActionEvent e) {
429 				addTable();
430 			}
431 
432 		});
433 
434 		myCloseFileButton = new JButton("Close File");
435 		myCloseFileButton.setIcon(new ImageIcon(ConformanceEditorPanel.class.getResource("/ca/uhn/hl7v2/testpanel/images/close.png")));
436 		myCloseFileButton.addMouseListener(new HoverButtonMouseAdapter(myCloseFileButton));
437 		myCloseFileButton.addActionListener(new ActionListener() {
438 			public void actionPerformed(ActionEvent e) {
439 				Object selectedFileOrTable = getSelectedFileOrTable();
440 				if (selectedFileOrTable instanceof TableFile) {
441 					myController.closeFile((TableFile) selectedFileOrTable);
442 				} else if (selectedFileOrTable instanceof Table) {
443 					myController.closeFile(((Table) selectedFileOrTable).getTableFile());
444 				}
445 			}
446 		});
447 		myCloseFileButton.setBorderPainted(false);
448 		toolBar.add(myCloseFileButton);
449 		
450 		Component horizontalStrut_1 = Box.createHorizontalStrut(20);
451 		horizontalStrut_1.setMaximumSize(new Dimension(100, 32767));
452 		horizontalStrut_1.setPreferredSize(new Dimension(100, 0));
453 		horizontalStrut_1.setMinimumSize(new Dimension(100, 0));
454 		toolBar.add(horizontalStrut_1);
455 
456 		myAddTableButton.setBorderPainted(false);
457 		myAddTableButton.setIcon(new ImageIcon(ConformanceEditorPanel.class.getResource("/ca/uhn/hl7v2/testpanel/images/table.png")));
458 		myAddTableButton.addMouseListener(new HoverButtonMouseAdapter(myAddTableButton));
459 		toolBar.add(myAddTableButton);
460 
461 		myCloseTableButton = new JButton("Remove Table");
462 		myCloseTableButton.setIcon(new ImageIcon(ConformanceEditorPanel.class.getResource("/ca/uhn/hl7v2/testpanel/images/close.png")));
463 		myCloseTableButton.setBorderPainted(false);
464 		myCloseTableButton.addMouseListener(new HoverButtonMouseAdapter(myCloseTableButton));
465 		myCloseTableButton.addActionListener(new ActionListener() {
466 			public void actionPerformed(ActionEvent theE) {
467 				TableFile tableFile;
468 				Object sel = getSelectedFileOrTable();
469 				Table table;
470 				if (sel instanceof Table) {
471 					table = (Table) sel;
472 					tableFile = table.getTableFile();
473 				} else {
474 					return;
475 				}
476 				tableFile.removeTable(table);
477 				myController.markFileForSaving(tableFile);
478 			}
479 		});
480 		toolBar.add(myCloseTableButton);
481 
482 		JScrollPane scrollPane = new JScrollPane();
483 		GridBagConstraints gbc_scrollPane = new GridBagConstraints();
484 		gbc_scrollPane.gridheight = 2;
485 		gbc_scrollPane.insets = new Insets(0, 0, 0, 5);
486 		gbc_scrollPane.fill = GridBagConstraints.BOTH;
487 		gbc_scrollPane.gridx = 0;
488 		gbc_scrollPane.gridy = 2;
489 		tablesPanel.add(scrollPane, gbc_scrollPane);
490 
491 		myTableFilesTable = new JTree();
492 		myTableFilesTable.addTreeSelectionListener(new TreeSelectionListener() {
493 			public void valueChanged(TreeSelectionEvent e) {
494 				updateSelectedCodesItem();
495 			}
496 		});
497 		myTableFilesTable.setCellRenderer(new TableTreeRenderer());
498 		myTableFilesTable.setShowsRootHandles(true);
499 		myTableFilesTable.setRootVisible(false);
500 		myTableFilesTable.setModel(myTableFilesTreeModel);
501 		scrollPane.setViewportView(myTableFilesTable);
502 
503 		JLabel lblNewLabel = new JLabel(
504 				"<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>");
505 		GridBagConstraints gbc_lblNewLabel = new GridBagConstraints();
506 		gbc_lblNewLabel.fill = GridBagConstraints.HORIZONTAL;
507 		gbc_lblNewLabel.insets = new Insets(0, 0, 5, 5);
508 		gbc_lblNewLabel.gridx = 0;
509 		gbc_lblNewLabel.gridy = 0;
510 		tablesPanel.add(lblNewLabel, gbc_lblNewLabel);
511 
512 		myRightCardPanel = new JPanel();
513 		GridBagConstraints gbc_RightCardPanel = new GridBagConstraints();
514 		gbc_RightCardPanel.gridheight = 4;
515 		gbc_RightCardPanel.fill = GridBagConstraints.BOTH;
516 		gbc_RightCardPanel.gridx = 2;
517 		gbc_RightCardPanel.gridy = 0;
518 		tablesPanel.add(myRightCardPanel, gbc_RightCardPanel);
519 		myRightCardPanel.setLayout(new CardLayout(0, 0));
520 
521 		myCodesPanel = new JPanel();
522 		myRightCardPanel.add(myCodesPanel, CARD_CODES);
523 		GridBagLayout gbl_CodesPanel = new GridBagLayout();
524 		gbl_CodesPanel.columnWidths = new int[] { 0, 0, 0 };
525 		gbl_CodesPanel.rowHeights = new int[] { 0, 0, 0, 0, 0 };
526 		gbl_CodesPanel.columnWeights = new double[] { 0.0, 1.0, Double.MIN_VALUE };
527 		gbl_CodesPanel.rowWeights = new double[] { 0.0, 0.0, 0.0, 1.0, Double.MIN_VALUE };
528 		myCodesPanel.setLayout(gbl_CodesPanel);
529 
530 		JLabel lblValues = new JLabel("Codes");
531 		GridBagConstraints gbc_lblValues = new GridBagConstraints();
532 		gbc_lblValues.gridwidth = 2;
533 		gbc_lblValues.insets = new Insets(0, 0, 5, 5);
534 		gbc_lblValues.gridx = 0;
535 		gbc_lblValues.gridy = 0;
536 		myCodesPanel.add(lblValues, gbc_lblValues);
537 
538 		JLabel lblTable = new JLabel("Table");
539 		GridBagConstraints gbc_lblTable = new GridBagConstraints();
540 		gbc_lblTable.insets = new Insets(0, 0, 5, 5);
541 		gbc_lblTable.gridx = 0;
542 		gbc_lblTable.gridy = 1;
543 		myCodesPanel.add(lblTable, gbc_lblTable);
544 
545 		myTableIdTextField = new JTextField();
546 		GridBagConstraints gbc_TableIdTextField = new GridBagConstraints();
547 		gbc_TableIdTextField.insets = new Insets(0, 0, 5, 0);
548 		gbc_TableIdTextField.fill = GridBagConstraints.HORIZONTAL;
549 		gbc_TableIdTextField.gridx = 1;
550 		gbc_TableIdTextField.gridy = 1;
551 		myCodesPanel.add(myTableIdTextField, gbc_TableIdTextField);
552 		myTableIdTextField.setColumns(10);
553 		myTableIdTextField.getDocument().addDocumentListener(new SimpleDocumentListener() {
554 			@Override
555 			public void update(DocumentEvent theE) {
556 				if (myRespondingToChange) {
557 					return;
558 				}
559 				if (getSelectedFileOrTable() instanceof Table) {
560 					Table table = (Table) getSelectedFileOrTable();
561 					table.setCodeSystemId(myTableIdTextField.getText());
562 					myController.markFileForSaving(table.getTableFile());
563 				}
564 			}
565 		});
566 
567 		JLabel lblName = new JLabel("Name");
568 		GridBagConstraints gbc_lblName = new GridBagConstraints();
569 		gbc_lblName.insets = new Insets(0, 0, 5, 5);
570 		gbc_lblName.gridx = 0;
571 		gbc_lblName.gridy = 2;
572 		myCodesPanel.add(lblName, gbc_lblName);
573 
574 		myTableNameTextField = new JTextField();
575 		GridBagConstraints gbc_TableNameTextField = new GridBagConstraints();
576 		gbc_TableNameTextField.insets = new Insets(0, 0, 5, 0);
577 		gbc_TableNameTextField.fill = GridBagConstraints.HORIZONTAL;
578 		gbc_TableNameTextField.gridx = 1;
579 		gbc_TableNameTextField.gridy = 2;
580 		myCodesPanel.add(myTableNameTextField, gbc_TableNameTextField);
581 		myTableNameTextField.setColumns(10);
582 		myTableNameTextField.getDocument().addDocumentListener(new SimpleDocumentListener() {
583 			@Override
584 			public void update(DocumentEvent theE) {
585 				if (myRespondingToChange) {
586 					return;
587 				}
588 				if (getSelectedFileOrTable() instanceof Table) {
589 					Table table = (Table) getSelectedFileOrTable();
590 					table.setCodeSystemName(myTableNameTextField.getText());
591 					myController.markFileForSaving(table.getTableFile());
592 				}
593 			}
594 		});
595 
596 		JScrollPane scrollPane_1 = new JScrollPane();
597 		GridBagConstraints gbc_scrollPane_1 = new GridBagConstraints();
598 		gbc_scrollPane_1.fill = GridBagConstraints.BOTH;
599 		gbc_scrollPane_1.gridwidth = 2;
600 		gbc_scrollPane_1.gridx = 0;
601 		gbc_scrollPane_1.gridy = 3;
602 		myCodesPanel.add(scrollPane_1, gbc_scrollPane_1);
603 
604 		myCodesTable = new JTable();
605 		myCodesTable.setGridColor(Color.LIGHT_GRAY);
606 		scrollPane_1.setViewportView(myCodesTable);
607 		myCodesTable.setModel(myCodesTableModel);
608 
609 		myTableFilePanel = new JPanel();
610 		myRightCardPanel.add(myTableFilePanel, CARD_TABLE_FILE);
611 		GridBagLayout gbl_TableFilePanel = new GridBagLayout();
612 		gbl_TableFilePanel.columnWidths = new int[] { 0, 0, 0 };
613 		gbl_TableFilePanel.rowHeights = new int[] { 0, 0, 0 };
614 		gbl_TableFilePanel.columnWeights = new double[] { 0.0, 1.0, Double.MIN_VALUE };
615 		gbl_TableFilePanel.rowWeights = new double[] { 0.0, 0.0, Double.MIN_VALUE };
616 		myTableFilePanel.setLayout(gbl_TableFilePanel);
617 
618 		JLabel lblTable_1 = new JLabel("Table");
619 		lblTable_1.setHorizontalAlignment(SwingConstants.CENTER);
620 		GridBagConstraints gbc_lblTable_1 = new GridBagConstraints();
621 		gbc_lblTable_1.insets = new Insets(0, 0, 5, 0);
622 		gbc_lblTable_1.fill = GridBagConstraints.HORIZONTAL;
623 		gbc_lblTable_1.gridwidth = 2;
624 		gbc_lblTable_1.gridx = 0;
625 		gbc_lblTable_1.gridy = 0;
626 		myTableFilePanel.add(lblTable_1, gbc_lblTable_1);
627 
628 		JLabel lblName_1 = new JLabel("Name");
629 		GridBagConstraints gbc_lblName_1 = new GridBagConstraints();
630 		gbc_lblName_1.anchor = GridBagConstraints.EAST;
631 		gbc_lblName_1.insets = new Insets(0, 0, 0, 5);
632 		gbc_lblName_1.gridx = 0;
633 		gbc_lblName_1.gridy = 1;
634 		myTableFilePanel.add(lblName_1, gbc_lblName_1);
635 
636 		myTableFileNameTextF = new JTextField();
637 		GridBagConstraints gbc_TableFileNameTextF = new GridBagConstraints();
638 		gbc_TableFileNameTextF.fill = GridBagConstraints.HORIZONTAL;
639 		gbc_TableFileNameTextF.gridx = 1;
640 		gbc_TableFileNameTextF.gridy = 1;
641 		myTableFilePanel.add(myTableFileNameTextF, gbc_TableFileNameTextF);
642 		myTableFileNameTextF.setColumns(10);
643 		myTableFileNameTextF.getDocument().addDocumentListener(new SimpleDocumentListener() {
644 			@Override
645 			public void update(DocumentEvent theE) {
646 				if (myRespondingToChange) {
647 					return;
648 				}
649 				if (getSelectedFileOrTable() instanceof TableFile) {
650 					TableFile file = (TableFile) getSelectedFileOrTable();
651 					file.setName(myTableFileNameTextF.getText());
652 					myController.markFileForSaving(file);
653 				}
654 			}
655 		});
656 
657 		myBlankPanel = new JPanel();
658 		myRightCardPanel.add(myBlankPanel, CARD_BLANK);
659 
660 		JPanel controlButtonsPanel = new JPanel();
661 		myframe.getContentPane().add(controlButtonsPanel, BorderLayout.SOUTH);
662 		GridBagLayout gbl_controlButtonsPanel = new GridBagLayout();
663 		gbl_controlButtonsPanel.columnWidths = new int[] { 0, 0, 0, 0 };
664 		gbl_controlButtonsPanel.rowHeights = new int[] { 0, 0 };
665 		gbl_controlButtonsPanel.columnWeights = new double[] { 1.0, 0.0, 0.0, Double.MIN_VALUE };
666 		gbl_controlButtonsPanel.rowWeights = new double[] { 0.0, Double.MIN_VALUE };
667 		controlButtonsPanel.setLayout(gbl_controlButtonsPanel);
668 
669 		JButton saveButton = new JButton("Close");
670 		saveButton.addActionListener(new ActionListener() {
671 			public void actionPerformed(ActionEvent e) {
672 				myframe.setVisible(false);
673 			}
674 		});
675 		GridBagConstraints gbc_saveButton = new GridBagConstraints();
676 		gbc_saveButton.gridx = 2;
677 		gbc_saveButton.gridy = 0;
678 		controlButtonsPanel.add(saveButton, gbc_saveButton);
679 
680 	}
681 
682 	private void newProfileGroup() {
683 		myController.newProfileGroup();
684 	}
685 
686 	public void show() {
687 		myframe.setVisible(true);
688 
689 		updateFileTree(null);
690 		updateSelectedCodesItem();
691 		updateSelectedProfilesItem();
692 	}
693 
694 	private void updateFileTree(Object theSelectedObject) {
695 
696 		List<TableFile> tableFiles = myController.getTableFileList().getTableFiles();
697 		int row = 0;
698 		for (int i = 0; i < tableFiles.size(); i++) {
699 			TableFile nextFile = tableFiles.get(i);
700 
701 			if (myTableFilesTreeRoot.getChildCount() <= i || ((DefaultMutableTreeNode) myTableFilesTreeRoot.getChildAt(i)).getUserObject() != nextFile) {
702 				myTableFilesTreeRoot.insert(new DefaultMutableTreeNode(nextFile), i);
703 				nextFile.addPropertyChangeListener(TableFile.PROP_TABLES, new PropertyChangeListener() {
704 					public void propertyChange(PropertyChangeEvent theEvt) {
705 						updateFileTree(null);
706 					}
707 				});
708 			}
709 
710 			DefaultMutableTreeNode nextNode = (DefaultMutableTreeNode) myTableFilesTreeRoot.getChildAt(i);
711 			if (nextNode.getUserObject() == theSelectedObject) {
712 				myTableFilesTable.expandRow(row);
713 				myTableFilesTable.setSelectionRow(row);
714 			} else {
715 				myTableFilesTable.collapseRow(row);
716 			}
717 
718 			final int parentRow = row;
719 
720 			DefaultMutableTreeNode nextFileNode = (DefaultMutableTreeNode) myTableFilesTreeRoot.getChildAt(i);
721 			for (int j = 0; j < nextFile.getTables().size(); j++) {
722 
723 				Table nextTable = nextFile.getTables().get(j);
724 				if (nextFileNode.getChildCount() <= j || ((DefaultMutableTreeNode) nextFileNode.getChildAt(j)).getUserObject() != nextTable) {
725 					nextFileNode.insert(new DefaultMutableTreeNode(nextTable), j);
726 					nextTable.addPropertyChangeListener(Table.PROP_CODES, new PropertyChangeListener() {
727 
728 						public void propertyChange(PropertyChangeEvent theEvt) {
729 							myTableFilesTable.repaint();
730 						}
731 					});
732 				}
733 
734 				while (nextFileNode.getChildCount() > nextFile.getTables().size()) {
735 					nextFileNode.remove(nextFile.getTables().size());
736 				}
737 
738 				row++;
739 
740 				DefaultMutableTreeNode nextTableNode = (DefaultMutableTreeNode) nextFileNode.getChildAt(j);
741 				if (nextTableNode.getUserObject() == theSelectedObject) {
742 					final int curRow = row;
743 					EventQueue.invokeLater(new Runnable() {
744 						public void run() {
745 							myTableFilesTable.expandRow(parentRow);
746 							myTableFilesTable.setSelectionInterval(curRow, curRow);
747 						}
748 					});
749 				}
750 
751 			}
752 
753 			row++;
754 		}
755 
756 		while (myTableFilesTreeRoot.getChildCount() > tableFiles.size()) {
757 			myTableFilesTreeRoot.remove(tableFiles.size());
758 		}
759 
760 		myTableFilesTreeModel.nodeStructureChanged(myTableFilesTreeRoot);
761 	}
762 
763 	private void updateProfileTree(Object theSelectedObject) {
764 
765 		List<ProfileGroup> profileFiles = myController.getProfileFileList().getProfiles();
766 		int row = 0;
767 		for (int i = 0; i < profileFiles.size(); i++) {
768 			final ProfileGroup nextGroup = profileFiles.get(i);
769 
770 			if (myProfilesOutlineRoot.getChildCount() <= i || ((DefaultMutableTreeNode) myProfilesOutlineRoot.getChildAt(i)).getUserObject() != nextGroup) {
771 				myProfilesOutlineRoot.insert(new ProfileGroupNode(nextGroup), i);
772 				nextGroup.addPropertyChangeListener(ProfileGroup.PROP_PROFILES, new PropertyChangeListener() {
773 					public void propertyChange(PropertyChangeEvent theEvt) {
774 						updateProfileTree(theEvt.getNewValue());
775 					}
776 				});
777 			}
778 
779 			DefaultMutableTreeNode nextNode = (DefaultMutableTreeNode) myProfilesOutlineRoot.getChildAt(i);
780 			final AbstractLayoutCache layout = myProfilesOutlineModel.getLayout();
781 			TreePath path = layout.getPathForRow(row);
782 			if (nextNode.getUserObject() == theSelectedObject) {
783 				myProfilesOutline.expandPath(path);
784 				myProfilesOutline.getSelectionModel().setSelectionInterval(row, row);
785 			} else {
786 				myProfilesOutline.collapsePath(path);
787 			}
788 
789 			final int parentRow = row;
790 
791 			ProfileGroupNode nextFileNode = (ProfileGroupNode) myProfilesOutlineRoot.getChildAt(i);
792 			for (int j = 0; j < nextGroup.getEntries().size(); j++) {
793 
794 				Entry nextEntry = nextGroup.getEntries().get(j);
795 				if (nextFileNode.getChildCount() <= j || ((DefaultMutableTreeNode) nextFileNode.getChildAt(j)).getUserObject() != nextEntry) {
796 					nextFileNode.insert(new ProfileNode(nextEntry), j);
797 					nextEntry.addPropertyChangeListener(ProfileGroup.Entry.PROP_DESC, new PropertyChangeListener() {
798 
799 						public void propertyChange(PropertyChangeEvent theEvt) {
800 							myProfilesOutline.repaint();
801 						}
802 					});
803 				}
804 
805 				row++;
806 
807 				DefaultMutableTreeNode nextTableNode = (DefaultMutableTreeNode) nextFileNode.getChildAt(j);
808 				if (nextTableNode.getUserObject() == theSelectedObject) {
809 					final int curRow = row;
810 					EventQueue.invokeLater(new Runnable() {
811 						public void run() {
812 							TreePath path = layout.getPathForRow(parentRow);
813 							myProfilesOutline.expandPath(path);
814 							myProfilesOutline.getSelectionModel().setSelectionInterval(curRow, curRow);
815 						}
816 					});
817 				}
818 
819 			}
820 
821 			while (nextFileNode.getChildCount() > nextGroup.getEntries().size()) {
822 				nextFileNode.remove(nextGroup.getEntries().size());
823 			}
824 
825 			row++;
826 		}
827 
828 		while (myProfilesOutlineRoot.getChildCount() > profileFiles.size()) {
829 			myProfilesOutlineRoot.remove(profileFiles.size());
830 		}
831 
832 		myProfilesOutlineTreeModel.reload();
833 	}
834 
835 	private void updateSelectedCodesItem() {
836 		myRespondingToChange = true;
837 		CardLayout cl = (CardLayout) (myRightCardPanel.getLayout());
838 
839 		Object selectedItem = getSelectedFileOrTable();
840 		if (selectedItem instanceof Table) {
841 
842 			Table table = (Table) selectedItem;
843 			myTableIdTextField.setText(table.getCodeSystemId());
844 			myTableNameTextField.setText(table.getCodeSystemName());
845 			myCodesTableModel.setTable(table);
846 			myAddTableButton.setEnabled(true);
847 			myCloseFileButton.setEnabled(true);
848 			myCloseTableButton.setEnabled(true);
849 
850 			cl.show(myRightCardPanel, CARD_CODES);
851 
852 		} else if (selectedItem instanceof TableFile) {
853 
854 			TableFile tf = (TableFile) selectedItem;
855 			myTableFileNameTextF.setText(tf.getName());
856 			cl.show(myRightCardPanel, CARD_TABLE_FILE);
857 			myAddTableButton.setEnabled(true);
858 			myCloseFileButton.setEnabled(true);
859 			myCloseTableButton.setEnabled(false);
860 
861 		} else {
862 
863 			cl.show(myRightCardPanel, CARD_BLANK);
864 			myAddTableButton.setEnabled(false);
865 			myCloseFileButton.setEnabled(false);
866 			myCloseTableButton.setEnabled(false);
867 
868 		}
869 
870 		myRespondingToChange = false;
871 	}
872 
873 	private void updateSelectedProfilesItem() {
874 
875 		Object sel = getSelectedProfileGroupOrFile();
876 		if (sel instanceof ProfileGroup) {
877 			myExportButton.setEnabled(true);
878 			myRemoveProfileGroupButton.setEnabled(true);
879 			myRemoveProfileButton.setEnabled(false);
880 			myAddProfileButton.setEnabled(true);
881 			myRenameButton.setEnabled(true);
882 		} else if (sel instanceof ProfileGroup.Entry) {
883 			myExportButton.setEnabled(false);
884 			myRemoveProfileGroupButton.setEnabled(false);
885 			myRemoveProfileButton.setEnabled(true);
886 			myAddProfileButton.setEnabled(true);
887 			myRenameButton.setEnabled(false);
888 		} else {
889 			myExportButton.setEnabled(false);
890 			myRemoveProfileGroupButton.setEnabled(false);
891 			myRemoveProfileButton.setEnabled(false);
892 			myAddProfileButton.setEnabled(false);
893 			myRenameButton.setEnabled(false);
894 		}
895 
896 	}
897 
898 	private class MyCodesTableModel extends DefaultTableModel {
899 
900 		private Table myTable;
901 
902 		public MyCodesTableModel() {
903 			addColumn("Code");
904 			addColumn("Name");
905 		}
906 
907 		@Override
908 		public int getRowCount() {
909 			if (myTable == null) {
910 				return 0;
911 			}
912 			return myTable.getCodes().size() + 1;
913 		}
914 
915 		@Override
916 		public Object getValueAt(int theRow, int theColumn) {
917 			if (myTable.getCodes().size() == theRow) {
918 				return "";
919 			}
920 
921 			Code code = myTable.getCodes().get(theRow);
922 			switch (theColumn) {
923 			case 0:
924 				return code.getCode();
925 			case 1:
926 				return code.getDisplayName();
927 			}
928 
929 			return "";
930 		}
931 
932 		@Override
933 		public boolean isCellEditable(int theRow, int theColumn) {
934 			return true;
935 		}
936 
937 		private void setTable(Table theTable) {
938 			if (myTable != theTable) {
939 				myTable = theTable;
940 				fireTableDataChanged();
941 			}
942 		}
943 
944 		@Override
945 		public void setValueAt(Object theAValue, int theRow, int theColumn) {
946 			Code code;
947 			if (myTable.getCodes().size() == theRow) {
948 				code = new Code();
949 				myTable.addCode(code);
950 			}
951 
952 			code = myTable.getCodes().get(theRow);
953 
954 			switch (theColumn) {
955 			case 0:
956 				code.setCode(theAValue.toString());
957 				break;
958 			case 1:
959 				code.setDisplayName(theAValue.toString());
960 				break;
961 			}
962 
963 			myController.markFileForSaving(myTable.getTableFile());
964 		}
965 
966 	}
967 
968 	public class MyProfilesOutlineModel extends DefaultOutlineModel {
969 
970 		protected MyProfilesOutlineModel(TreeModel theTreeModel) {
971 			super(theTreeModel, new MyProfilesRowModel(), false, "Profiles");
972 		}
973 
974 		@Override
975 		public boolean isCellEditable(int theRowIndex, int theColumnIndex) {
976 			if (theColumnIndex == 0) {
977 				DefaultMutableTreeNode selectedNode = getNodeForRow(theRowIndex);
978 				if (selectedNode instanceof ProfileGroupNode) {
979 					return true;
980 				} else {
981 					return false;
982 				}
983 			}
984 			return super.isCellEditable(theRowIndex, theColumnIndex);
985 		}
986 
987 		@Override
988 		protected void setTreeValueAt(Object theAValue, int theRowIndex) {
989 			DefaultMutableTreeNode selectedNode = getNodeForRow(theRowIndex);
990 			if (selectedNode instanceof ProfileGroupNode) {
991 				((ProfileGroupNode) selectedNode).getUserObject().setName(theAValue.toString());
992 			} else {
993 				ourLog.error("Unknown type {}", selectedNode.getClass());
994 			}
995 
996 			myController.getProfileFileList().updatePrefs();
997 		}
998 	}
999 
1000 	private class MyProfilesOutlinesRenderProvider implements RenderDataProvider {
1001 
1002 		public Color getBackground(Object theArg0) {
1003 			return Color.white;
1004 		}
1005 
1006 		public String getDisplayName(Object theArg0) {
1007 			if (theArg0 instanceof ProfileGroupNode) {
1008 				return ((ProfileGroupNode) theArg0).getUserObject().getName();
1009 			}
1010 
1011 			if (theArg0 instanceof ProfileNode) {
1012 				ProfileProxy profileProxy = ((ProfileNode) theArg0).getUserObject().getProfileProxy();
1013 				return profileProxy.getName();
1014 			}
1015 
1016 			return "Unknown";
1017 		}
1018 
1019 		public Color getForeground(Object theArg0) {
1020 			return Color.black;
1021 		}
1022 
1023 		public Icon getIcon(Object theArg0) {
1024 			if (theArg0 instanceof ProfileGroupNode) {
1025 				return ImageFactory.getProfileGroup();
1026 			} else {
1027 				return ImageFactory.getProfile();
1028 			}
1029 		}
1030 
1031 		public String getTooltipText(Object theArg0) {
1032 			return null;
1033 		}
1034 
1035 		public boolean isHtmlDisplayName(Object theArg0) {
1036 			return true;
1037 		}
1038 
1039 	}
1040 
1041 	public class MyProfilesRowModel implements RowModel {
1042 
1043 		public static final int COL_MSG_TYPE = 0;
1044 		public static final int COL_TABLES = 2;
1045 		public static final int COL_TRIGGER = 1;
1046 
1047 		public Class<?> getColumnClass(int theArg0) {
1048 			return String.class;
1049 		}
1050 
1051 		public int getColumnCount() {
1052 			return 3;
1053 		}
1054 
1055 		public String getColumnName(int theArg0) {
1056 			switch (theArg0) {
1057 			case COL_MSG_TYPE:
1058 				return "Msg Type";
1059 			case COL_TRIGGER:
1060 				return "Trigger";
1061 			case COL_TABLES:
1062 				return "Table File";
1063 			}
1064 			return null;
1065 		}
1066 
1067 		public Object getValueFor(Object theNode, int theColumn) {
1068 			if (theNode instanceof ProfileNode) {
1069 				ProfileNode pn = (ProfileNode) theNode;
1070 				switch (theColumn) {
1071 				case COL_MSG_TYPE:
1072 					return pn.getUserObject().getMessageType();
1073 				case COL_TRIGGER:
1074 					return pn.getUserObject().getEventType();
1075 				case COL_TABLES:
1076 					String tableFileId = pn.getUserObject().getTablesId();
1077 					if (tableFileId == null) {
1078 						return null;
1079 					}
1080 					TableFile tableFile = myController.getTableFileList().getTableFile(tableFileId);
1081 					if (tableFile == null) {
1082 						return null;
1083 					}
1084 					return tableFile.getName();
1085 				}
1086 			}
1087 			return null;
1088 		}
1089 
1090 		public boolean isCellEditable(Object theNode, int theColumn) {
1091 			if (theNode instanceof ProfileGroupNode) {
1092 				return false;
1093 			} else if (theNode instanceof ProfileNode) {
1094 				return true;
1095 			} else {
1096 				ourLog.error("Unknown type {}", theNode.getClass());
1097 				return false;
1098 			}
1099 		}
1100 
1101 		public void setValueFor(Object theNode, int theColumn, Object theValue) {
1102 			if (theNode instanceof ProfileNode) {
1103 				ProfileNode pn = (ProfileNode) theNode;
1104 				switch (theColumn) {
1105 				case COL_MSG_TYPE:
1106 					pn.getUserObject().setMessageType(theValue.toString());
1107 					break;
1108 				case COL_TRIGGER:
1109 					pn.getUserObject().setEventType(theValue.toString());
1110 					break;
1111 				case COL_TABLES:
1112 					if (TBL_OPT_NONE.equals(theValue.toString())) {
1113 						pn.getUserObject().setTablesId(null);
1114 					} else if (theValue.toString().contains(":") == false) {
1115 						// the value isn't changing in this case
1116 						return;
1117 					} else {
1118 						String value = theValue.toString().replaceAll(":.*", "");
1119 						int index = Integer.parseInt(value) - 1;
1120 						String tblId = myController.getTableFileList().getTableFiles().get(index).getId();
1121 						pn.getUserObject().setTablesId(tblId);
1122 					}
1123 					break;
1124 				}
1125 
1126 				myController.getProfileFileList().updatePrefs();
1127 
1128 			}
1129 		}
1130 
1131 	}
1132 
1133 	public class MyProfilesTreeModel extends DefaultTreeModel {
1134 
1135 		public MyProfilesTreeModel() {
1136 			super(myProfilesOutlineRoot);
1137 		}
1138 
1139 	}
1140 
1141 	private static final String TBL_OPT_NONE = "None";
1142 
1143 	public class ProfileGroupCellComboboxEditor extends DefaultCellEditor {
1144 
1145 		public ProfileGroupCellComboboxEditor() {
1146 			super(new JComboBox());
1147 		}
1148 
1149 		private List<String> getSortedStructures() {
1150 			ArrayList<String> retVal = new ArrayList<String>();
1151 			try {
1152 				for (String next : EventMapUtil.getEventMap(Version.latestVersion().getVersion()).keySet()) {
1153 					retVal.add(next);
1154 				}
1155 			} catch (HL7Exception e) {
1156 				ourLog.error("Failed to load structures", e);
1157 			}
1158 
1159 			Collections.sort(retVal);
1160 
1161 			return retVal;
1162 		}
1163 
1164 		/*
1165 		 * (non-Javadoc)
1166 		 * 
1167 		 * @see
1168 		 * javax.swing.DefaultCellEditor#getTableCellEditorComponent(javax.swing
1169 		 * .JTable, java.lang.Object, boolean, int, int)
1170 		 */
1171 		@Override
1172 		public Component getTableCellEditorComponent(JTable theTable, Object theValue, boolean theIsSelected, int theRow, int theColumn) {
1173 
1174 			final AbstractLayoutCache layout = myProfilesOutlineModel.getLayout();
1175 			TreePath selectionPath = layout.getPathForRow(theRow);
1176 			ProfileNode selectedNode = (ProfileNode) selectionPath.getLastPathComponent();
1177 
1178 			JComboBox retVal = (JComboBox) super.getTableCellEditorComponent(theTable, theValue, theIsSelected, theRow, theColumn);
1179 			retVal.removeAllItems();
1180 
1181 //			Properties structures = new Properties();
1182 //			try {
1183 //				structures = Parser.getMessageStructures(Version.latestVersion().getVersion());
1184 //			} catch (IOException e) {
1185 //				ourLog.error("Failed to load message types", e);
1186 //			}
1187 
1188 			if (theColumn - 1 == MyProfilesRowModel.COL_MSG_TYPE) {
1189 
1190 				if (!"*".equals(theValue)) {
1191 					retVal.addItem("*");
1192 				}
1193 
1194 				if (!ACK.equals(theValue)) {
1195 					retVal.addItem(ACK);
1196 				}
1197 
1198 				String prevKey = "";
1199 				for (String nextStruct : getSortedStructures()) {
1200 					String[] nextParts = nextStruct.split("_");
1201 					if (StringUtils.isNotBlank(nextParts[0]) && nextParts[0].equals(prevKey) == false) {
1202 						prevKey = nextParts[0];
1203 						retVal.addItem(prevKey);
1204 					}
1205 				}
1206 
1207 				retVal.setSelectedItem(theValue);
1208 
1209 			} else if (theColumn - 1 == MyProfilesRowModel.COL_TRIGGER) {
1210 
1211 				if (!"*".equals(theValue)) {
1212 					retVal.addItem("*");
1213 				}
1214 
1215 				for (String nextStruct : getSortedStructures()) {
1216 					String[] nextParts = nextStruct.split("_");
1217 					String selMsgType = selectedNode.getUserObject().getMessageType();
1218 					if (nextParts.length > 1 && StringUtils.isNotBlank(nextParts[0]) && StringUtils.isNotBlank(nextParts[1]) && (nextParts[0].equals(selMsgType) || "*".equals(selMsgType))) {
1219 						retVal.addItem(nextParts[1]);
1220 					}
1221 				}
1222 
1223 				retVal.setSelectedItem(theValue);
1224 
1225 			} else if (theColumn - 1 == MyProfilesRowModel.COL_TABLES) {
1226 
1227 				retVal.addItem(TBL_OPT_NONE);
1228 				retVal.setSelectedIndex(0);
1229 
1230 				for (int i = 1; i <= myController.getTableFileList().getTableFiles().size(); i++) {
1231 					TableFile tableFile = myController.getTableFileList().getTableFiles().get(i - 1);
1232 					retVal.addItem((i) + ": " + tableFile.getName());
1233 
1234 					if (tableFile.getId().equals(selectedNode.getUserObject().getTablesId())) {
1235 						retVal.setSelectedIndex(i);
1236 					}
1237 
1238 				}
1239 
1240 			}
1241 
1242 			return retVal;
1243 		}
1244 
1245 		/*
1246 		 * (non-Javadoc)
1247 		 * 
1248 		 * @see
1249 		 * javax.swing.DefaultCellEditor#getTreeCellEditorComponent(javax.swing
1250 		 * .JTree, java.lang.Object, boolean, boolean, boolean, int)
1251 		 */
1252 		@Override
1253 		public Component getTreeCellEditorComponent(JTree theTree, Object theValue, boolean theIsSelected, boolean theExpanded, boolean theLeaf, int theRow) {
1254 			return super.getTreeCellEditorComponent(theTree, theValue, theIsSelected, theExpanded, theLeaf, theRow);
1255 		}
1256 
1257 	}
1258 
1259 	private final class ProfileGroupCellEditor extends DefaultCellEditor {
1260 		public ProfileGroupCellEditor() {
1261 			super(new JTextField());
1262 			setClickCountToStart(1);
1263 		}
1264 
1265 		private ProfileGroupCellEditor(JTextField theTextField) {
1266 			super(theTextField);
1267 		}
1268 
1269 		@Override
1270 		public Component getTableCellEditorComponent(JTable theTable, Object theValue, boolean theIsSelected, int theRow, int theColumn) {
1271 			Component retVal = super.getTableCellEditorComponent(theTable, theValue, theIsSelected, theRow, theColumn);
1272 			if (theValue instanceof ProfileGroupNode) {
1273 				ProfileGroupNode value = (ProfileGroupNode) theValue;
1274 				((JTextField) retVal).setText(value.getUserObject().getName());
1275 				// } else {
1276 				// ProfileNode value = (ProfileNode) theValue;
1277 				// ((JTextField)
1278 				// retVal).setText(value.getUserObject().getName());
1279 			}
1280 			return retVal;
1281 		}
1282 
1283 		@Override
1284 		public Component getTreeCellEditorComponent(JTree theTree, Object theValue, boolean theIsSelected, boolean theExpanded, boolean theLeaf, int theRow) {
1285 			Component retVal = super.getTreeCellEditorComponent(theTree, theValue, theIsSelected, theExpanded, theLeaf, theRow);
1286 			return retVal;
1287 		}
1288 	}
1289 
1290 	public class ProfileGroupNode extends DefaultMutableTreeNode {
1291 		public ProfileGroupNode(ProfileGroup theProfileGroup) {
1292 			super(theProfileGroup);
1293 		}
1294 
1295 		@Override
1296 		public ProfileGroup getUserObject() {
1297 			return (ProfileGroup) super.getUserObject();
1298 		}
1299 	}
1300 
1301 	public class ProfileNode extends DefaultMutableTreeNode {
1302 		public ProfileNode(ProfileGroup.Entry theProfile) {
1303 			super(theProfile);
1304 		}
1305 
1306 		@Override
1307 		public ProfileGroup.Entry getUserObject() {
1308 			return (ProfileGroup.Entry) super.getUserObject();
1309 		}
1310 	}
1311 
1312 }