View Javadoc
1   /**
2    * The contents of this file are subject to the Mozilla Public License Version 1.1
3    * (the "License"); you may not use this file except in compliance with the License.
4    * You may obtain a copy of the License at http://www.mozilla.org/MPL/
5    * Software distributed under the License is distributed on an "AS IS" basis,
6    * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the
7    * specific language governing rights and limitations under the License.
8    *
9    * The Original Code is ""  Description:
10   * ""
11   *
12   * The Initial Developer of the Original Code is University Health Network. Copyright (C)
13   * 2001.  All Rights Reserved.
14   *
15   * Contributor(s): ______________________________________.
16   *
17   * Alternatively, the contents of this file may be used under the terms of the
18   * GNU General Public License (the  "GPL"), in which case the provisions of the GPL are
19   * applicable instead of those above.  If you wish to allow use of your version of this
20   * file only under the terms of the GPL and not to allow others to use your version
21   * of this file under the MPL, indicate your decision by deleting  the provisions above
22   * and replace  them with the notice and other provisions required by the GPL License.
23   * If you do not delete the provisions above, a recipient may use your version of
24   * this file under either the MPL or the GPL.
25   */
26  package ca.uhn.hl7v2.testpanel.ui.editor;
27  
28  import java.awt.BorderLayout;
29  import java.awt.Color;
30  import java.awt.Component;
31  import java.awt.Dimension;
32  import java.awt.EventQueue;
33  import java.awt.Font;
34  import java.awt.Frame;
35  import java.awt.GridBagConstraints;
36  import java.awt.GridBagLayout;
37  import java.awt.Insets;
38  import java.awt.Point;
39  import java.awt.SystemColor;
40  import java.awt.Toolkit;
41  import java.awt.datatransfer.Clipboard;
42  import java.awt.datatransfer.StringSelection;
43  import java.awt.event.ActionEvent;
44  import java.awt.event.ActionListener;
45  import java.awt.event.MouseAdapter;
46  import java.awt.event.MouseEvent;
47  import java.beans.PropertyChangeEvent;
48  import java.beans.PropertyChangeListener;
49  import java.util.ArrayList;
50  import java.util.List;
51  
52  import javax.swing.Box;
53  import javax.swing.ButtonGroup;
54  import javax.swing.DefaultComboBoxModel;
55  import javax.swing.ImageIcon;
56  import javax.swing.JButton;
57  import javax.swing.JComboBox;
58  import javax.swing.JEditorPane;
59  import javax.swing.JLabel;
60  import javax.swing.JMenuItem;
61  import javax.swing.JPanel;
62  import javax.swing.JPopupMenu;
63  import javax.swing.JRadioButton;
64  import javax.swing.JScrollBar;
65  import javax.swing.JScrollPane;
66  import javax.swing.JSplitPane;
67  import javax.swing.JTabbedPane;
68  import javax.swing.JToggleButton;
69  import javax.swing.JToolBar;
70  import javax.swing.SwingConstants;
71  import javax.swing.SwingUtilities;
72  import javax.swing.event.CaretEvent;
73  import javax.swing.event.CaretListener;
74  import javax.swing.event.DocumentEvent;
75  import javax.swing.event.DocumentListener;
76  import javax.swing.text.Highlighter;
77  
78  import jsyntaxpane.DefaultSyntaxKit;
79  
80  import org.apache.commons.lang.StringUtils;
81  import org.apache.commons.lang.Validate;
82  import org.slf4j.Logger;
83  import org.slf4j.LoggerFactory;
84  
85  import ca.uhn.hl7v2.conf.ProfileException;
86  import ca.uhn.hl7v2.testpanel.controller.Controller;
87  import ca.uhn.hl7v2.testpanel.controller.Prefs;
88  import ca.uhn.hl7v2.testpanel.model.conf.ProfileFileList;
89  import ca.uhn.hl7v2.testpanel.model.conf.ProfileGroup;
90  import ca.uhn.hl7v2.testpanel.model.conn.OutboundConnection;
91  import ca.uhn.hl7v2.testpanel.model.conn.OutboundConnectionList;
92  import ca.uhn.hl7v2.testpanel.model.msg.Hl7V2MessageCollection;
93  import ca.uhn.hl7v2.testpanel.ui.ActivityTable;
94  import ca.uhn.hl7v2.testpanel.ui.BaseMainPanel;
95  import ca.uhn.hl7v2.testpanel.ui.Er7SyntaxKit;
96  import ca.uhn.hl7v2.testpanel.ui.HoverButtonMouseAdapter;
97  import ca.uhn.hl7v2.testpanel.ui.IDestroyable;
98  import ca.uhn.hl7v2.testpanel.ui.ShowEnum;
99  import ca.uhn.hl7v2.testpanel.ui.v2tree.Hl7V2MessageTree;
100 import ca.uhn.hl7v2.testpanel.ui.v2tree.Hl7V2MessageTree.IWorkingListener;
101 import ca.uhn.hl7v2.testpanel.util.IOkCancelCallback;
102 import ca.uhn.hl7v2.testpanel.util.Range;
103 import ca.uhn.hl7v2.testpanel.xsd.Hl7V2EncodingTypeEnum;
104 import ca.uhn.hl7v2.validation.impl.DefaultValidation;
105 
106 public class Hl7V2MessageEditorPanel extends BaseMainPanel implements IDestroyable {
107 	private static final String CREATE_NEW_CONNECTION = "Create New Connection...";
108 	private static final String NO_CONNECTIONS = "No Connections";
109 	private static final Logger ourLog = LoggerFactory.getLogger(Hl7V2MessageEditorPanel.class);
110 	private SendOptionsPopupDialog mySendOptionsPopupDialog;
111 
112 	static {
113 
114 		System.setProperty("DefaultFont", "ARIAL-PLAIN-13");
115 
116 		try {
117 			DefaultSyntaxKit.initKit();
118 			DefaultSyntaxKit.registerContentType("text/er7", Er7SyntaxKit.class.getName());
119 			ourLog.info("Registered syntaxKit");
120 		} catch (Throwable e) {
121 			e.printStackTrace();
122 		}
123 		
124 	}
125 
126 	private boolean myDontRespondToSourceMessageChanges;
127 	private Component myhorizontalStrut_4;
128 	private JPanel bottomPanel;
129 	private JPanel messageEditorContainerPanel;
130 	private JComboBox myShowCombo;
131 	private Controller myController;
132 	private boolean myDisableCaretUpdateHandling;
133 	private DocumentListener myDocumentListener;
134 	private JToggleButton myFollowToggle;
135 	private JLabel mylabel;
136 	private JLabel mylabel_1;
137 	private JLabel mylabel_2;
138 	private JLabel mylabel_3;
139 	private Hl7V2MessageCollection myMessage;
140 	private JEditorPane myMessageEditor;
141 	private PropertyChangeListener myMessageListeneer;
142 	private JScrollPane myMessageScrollPane;
143 	private PropertyChangeListener myOutboundConnectionsListener;
144 	private JComboBox myOutboundInterfaceCombo;
145 	private DefaultComboBoxModel myOutboundInterfaceComboModel;
146 	private JComboBox myProfileCombobox;
147 	private ProfileComboModel myProfileComboboxModel;
148 	private PropertyChangeListener myRangeListener;
149 	private JRadioButton myRdbtnEr7;
150 	private JRadioButton myRdbtnXml;
151 	private PropertyChangeListener mySelectedPathListener;
152 	private JButton mySendButton;
153 	private JSplitPane mysplitPane;
154 	private JLabel myTerserPathTextField;
155 	private JToolBar mytoolBar;
156 	private Hl7V2MessageTree myTreePanel;
157 	private JScrollPane myTreeScrollPane;
158 	private JPanel treeContainerPanel;
159 	private JTabbedPane myTopTabBar;
160 	// private JPanel mySendingPanel;
161 	private ActivityTable mySendingActivityTable;
162 	private PropertyChangeListener myWindowTitleListener;
163 	private Component myhorizontalStrut;
164 	private Component myhorizontalStrut_1;
165 	private boolean myOutboundInterfaceComboModelIsUpdating;
166 	private ArrayList<OutboundConnection> myOutboundInterfaceComboModelShadow;
167 	private final JPopupMenu myTerserPathPopupMenu = new JPopupMenu();
168 	private boolean myHandlingProfileComboboxChange;
169 	private JLabel mylabel_4;
170 	private JToolBar mytoolBar_1;
171 	private TablesComboModel myTablesComboModel;
172 	private PropertyChangeListener myProfilesListener;
173 	private PropertyChangeListener myProfilesNamesListener;
174 	private JButton mySpinner;
175 	private Component myhorizontalGlue;
176 	private ImageIcon mySpinnerIconOn;
177 	private ImageIcon mySpinnerIconOff;
178 	private JButton collapseAllButton;
179 	private JButton expandAllButton;
180 	private Component myhorizontalStrut_2;
181 	private JButton mySendOptionsButton;
182 
183 	/**
184 	 * Create the panel.
185 	 */
186 	public Hl7V2MessageEditorPanel(final Controller theController) {
187 		setBorder(null);
188 		myController = theController;
189 
190 		ButtonGroup encGrp = new ButtonGroup();
191 		setLayout(new BorderLayout(0, 0));
192 
193 		mysplitPane = new JSplitPane();
194 		mysplitPane.setResizeWeight(0.5);
195 		mysplitPane.setOrientation(JSplitPane.VERTICAL_SPLIT);
196 		add(mysplitPane);
197 
198 		mysplitPane.addPropertyChangeListener(JSplitPane.DIVIDER_LOCATION_PROPERTY, new PropertyChangeListener() {
199 			public void propertyChange(PropertyChangeEvent theEvt) {
200 				double ratio = (double) mysplitPane.getDividerLocation() / mysplitPane.getHeight();
201 				ourLog.debug("Resizing split to ratio: {}", ratio);
202 				Prefs.getInstance().setHl7EditorSplit(ratio);
203 			}
204 		});
205 
206 		EventQueue.invokeLater(new Runnable() {
207 			public void run() {
208 				mysplitPane.setDividerLocation(Prefs.getInstance().getHl7EditorSplit());
209 			}
210 		});
211 
212 		messageEditorContainerPanel = new JPanel();
213 		messageEditorContainerPanel.setBorder(null);
214 		mysplitPane.setRightComponent(messageEditorContainerPanel);
215 		messageEditorContainerPanel.setLayout(new BorderLayout(0, 0));
216 
217 		myMessageEditor = new JEditorPane();
218 		Highlighter h = new UnderlineHighlighter();
219 		myMessageEditor.setHighlighter(h);
220 		// myMessageEditor.setFont(Prefs.getHl7EditorFont());
221 		myMessageEditor.setSelectedTextColor(Color.black);
222 
223 		myMessageEditor.setCaret(new EditorCaret());
224 		
225 		myMessageScrollPane = new JScrollPane(myMessageEditor);
226 		messageEditorContainerPanel.add(myMessageScrollPane);
227 
228 		JToolBar toolBar = new JToolBar();
229 		messageEditorContainerPanel.add(toolBar, BorderLayout.NORTH);
230 		toolBar.setFloatable(false);
231 		toolBar.setRollover(true);
232 
233 		myFollowToggle = new JToggleButton("Follow");
234 		myFollowToggle.setToolTipText("Keep the message tree (above) and the message editor (below) in sync");
235 		myFollowToggle.addActionListener(new ActionListener() {
236 			public void actionPerformed(ActionEvent e) {
237 				theController.setMessageEditorInFollowMode(myFollowToggle.isSelected());
238 			}
239 		});
240 		myFollowToggle.setIcon(new ImageIcon(Hl7V2MessageEditorPanel.class.getResource("/ca/uhn/hl7v2/testpanel/images/updown.png")));
241 		myFollowToggle.setSelected(theController.isMessageEditorInFollowMode());
242 		toolBar.add(myFollowToggle);
243 
244 		myhorizontalStrut = Box.createHorizontalStrut(20);
245 		toolBar.add(myhorizontalStrut);
246 
247 		mylabel_4 = new JLabel("Encoding");
248 		toolBar.add(mylabel_4);
249 
250 		myRdbtnEr7 = new JRadioButton("ER7");
251 		myRdbtnEr7.setMargin(new Insets(1, 2, 0, 1));
252 		toolBar.add(myRdbtnEr7);
253 
254 		myRdbtnXml = new JRadioButton("XML");
255 		myRdbtnXml.setMargin(new Insets(1, 5, 0, 1));
256 		toolBar.add(myRdbtnXml);
257 		encGrp.add(myRdbtnEr7);
258 		encGrp.add(myRdbtnXml);
259 
260 		treeContainerPanel = new JPanel();
261 		mysplitPane.setLeftComponent(treeContainerPanel);
262 		treeContainerPanel.setLayout(new BorderLayout(0, 0));
263 
264 		mySpinnerIconOn = new ImageIcon(Hl7V2MessageEditorPanel.class.getResource("/ca/uhn/hl7v2/testpanel/images/spinner.gif"));
265 		mySpinnerIconOff = new ImageIcon();
266 
267 		myTreePanel = new Hl7V2MessageTree(theController);
268 		myTreePanel.setWorkingListener(new IWorkingListener() {
269 
270 			public void startedWorking() {
271 				mySpinner.setText("");
272 				mySpinner.setIcon(mySpinnerIconOn);
273 				mySpinnerIconOn.setImageObserver(mySpinner);
274 			}
275 
276 
277 			public void finishedWorking(String theStatus) {
278 				mySpinner.setText(theStatus);
279 
280 				mySpinner.setIcon(mySpinnerIconOff);
281 				mySpinnerIconOn.setImageObserver(null);
282 			}
283 		});
284 		myTreeScrollPane = new JScrollPane(myTreePanel);
285 
286 		myTopTabBar = new JTabbedPane();
287 		treeContainerPanel.add(myTopTabBar);
288 		myTopTabBar.setBorder(null);
289 
290 		JPanel treeContainer = new JPanel();
291 		treeContainer.setLayout(new BorderLayout(0, 0));
292 		treeContainer.add(myTreeScrollPane);
293 
294 		myTopTabBar.add("Message Tree", treeContainer);
295 
296 		mytoolBar_1 = new JToolBar();
297 		mytoolBar_1.setFloatable(false);
298 		treeContainer.add(mytoolBar_1, BorderLayout.NORTH);
299 
300 		mylabel_3 = new JLabel("Show");
301 		mytoolBar_1.add(mylabel_3);
302 
303 		myShowCombo = new JComboBox();
304 		mytoolBar_1.add(myShowCombo);
305 		myShowCombo.setPreferredSize(new Dimension(130, 27));
306 		myShowCombo.setMinimumSize(new Dimension(130, 27));
307 		myShowCombo.setMaximumSize(new Dimension(130, 32767));
308 
309 		collapseAllButton = new JButton();
310 		collapseAllButton.setBorderPainted(false);
311 		collapseAllButton.addMouseListener(new HoverButtonMouseAdapter(collapseAllButton));
312 		collapseAllButton.addActionListener(new ActionListener() {
313 			public void actionPerformed(ActionEvent e) {
314 				myTreePanel.collapseAll();
315 			}
316 		});
317 		collapseAllButton.setToolTipText("Collapse All");
318 		collapseAllButton.setIcon(new ImageIcon(Hl7V2MessageEditorPanel.class.getResource("/ca/uhn/hl7v2/testpanel/images/collapse_all.png")));
319 		mytoolBar_1.add(collapseAllButton);
320 
321 		expandAllButton = new JButton();
322 		expandAllButton.setBorderPainted(false);
323 		expandAllButton.addMouseListener(new HoverButtonMouseAdapter(expandAllButton));
324 		expandAllButton.addActionListener(new ActionListener() {
325 			public void actionPerformed(ActionEvent e) {
326 				myTreePanel.expandAll();
327 			}
328 		});
329 		expandAllButton.setToolTipText("Expand All");
330 		expandAllButton.setIcon(new ImageIcon(Hl7V2MessageEditorPanel.class.getResource("/ca/uhn/hl7v2/testpanel/images/expand_all.png")));
331 		mytoolBar_1.add(expandAllButton);
332 
333 		myhorizontalGlue = Box.createHorizontalGlue();
334 		mytoolBar_1.add(myhorizontalGlue);
335 
336 		mySpinner = new JButton("");
337 		mySpinner.setForeground(Color.DARK_GRAY);
338 		mySpinner.setHorizontalAlignment(SwingConstants.RIGHT);
339 		mySpinner.setMaximumSize(new Dimension(200, 15));
340 		mySpinner.setPreferredSize(new Dimension(200, 15));
341 		mySpinner.setMinimumSize(new Dimension(200, 15));
342 		mySpinner.setBorderPainted(false);
343 		mySpinner.setSize(new Dimension(16, 16));
344 		mytoolBar_1.add(mySpinner);
345 		myProfileComboboxModel = new ProfileComboModel();
346 
347 		myTablesComboModel = new TablesComboModel(myController);
348 
349 		mytoolBar = new JToolBar();
350 		mytoolBar.setFloatable(false);
351 		mytoolBar.setRollover(true);
352 		treeContainerPanel.add(mytoolBar, BorderLayout.NORTH);
353 
354 		myOutboundInterfaceCombo = new JComboBox();
355 		myOutboundInterfaceComboModel = new DefaultComboBoxModel();
356 
357 		mylabel_1 = new JLabel("Send");
358 		mytoolBar.add(mylabel_1);
359 		myOutboundInterfaceCombo.setModel(myOutboundInterfaceComboModel);
360 		myOutboundInterfaceCombo.setMaximumSize(new Dimension(200, 32767));
361 		mytoolBar.add(myOutboundInterfaceCombo);
362 
363 		mySendButton = new JButton("Send");
364 		mySendButton.addMouseListener(new HoverButtonMouseAdapter(mySendButton));
365 		mySendButton.setBorderPainted(false);
366 		mySendButton.addActionListener(new ActionListener() {
367 			public void actionPerformed(ActionEvent e) {
368 				// int selectedIndex =
369 				// myOutboundInterfaceComboModel.getIndexOf(myOutboundInterfaceComboModel.getSelectedItem());
370 				int selectedIndex = myOutboundInterfaceCombo.getSelectedIndex();
371 				OutboundConnection connection = myController.getOutboundConnectionList().getConnections().get(selectedIndex);
372 				activateSendingActivityTabForConnection(connection);
373 				myController.sendMessages(connection, myMessage, mySendingActivityTable.provideTransmissionCallback());
374 			}
375 		});
376 
377 		myhorizontalStrut_2 = Box.createHorizontalStrut(20);
378 		myhorizontalStrut_2.setPreferredSize(new Dimension(2, 0));
379 		myhorizontalStrut_2.setMinimumSize(new Dimension(2, 0));
380 		myhorizontalStrut_2.setMaximumSize(new Dimension(2, 32767));
381 		mytoolBar.add(myhorizontalStrut_2);
382 
383 		mySendOptionsButton = new JButton("Options");
384 		mySendOptionsButton.setBorderPainted(false);
385 		final HoverButtonMouseAdapteroverButtonMouseAdapter">HoverButtonMouseAdapter sendOptionsHoverAdaptor = new HoverButtonMouseAdapter(mySendOptionsButton);
386 		mySendOptionsButton.addMouseListener(sendOptionsHoverAdaptor);
387 		mySendOptionsButton.setIcon(new ImageIcon(Hl7V2MessageEditorPanel.class.getResource("/ca/uhn/hl7v2/testpanel/images/sendoptions.png")));
388 		mytoolBar.add(mySendOptionsButton);
389 		mySendOptionsButton.addActionListener(new ActionListener() {
390 
391 			public void actionPerformed(ActionEvent theE) {
392 				if (mySendOptionsPopupDialog != null) {
393 					mySendOptionsPopupDialog.doHide();
394 					mySendOptionsPopupDialog = null;
395 					return;
396 				}
397 				mySendOptionsPopupDialog = new SendOptionsPopupDialog(Hl7V2MessageEditorPanel.this, myMessage, mySendOptionsButton, sendOptionsHoverAdaptor);
398 				Point los = mySendOptionsButton.getLocationOnScreen();
399 				mySendOptionsPopupDialog.setLocation(los.x, los.y + mySendOptionsButton.getHeight());
400 				mySendOptionsPopupDialog.setVisible(true);
401 			}
402 		});
403 
404 		mySendButton.setIcon(new ImageIcon(Hl7V2MessageEditorPanel.class.getResource("/ca/uhn/hl7v2/testpanel/images/button_execute.png")));
405 		mytoolBar.add(mySendButton);
406 
407 		myhorizontalStrut_1 = Box.createHorizontalStrut(20);
408 		mytoolBar.add(myhorizontalStrut_1);
409 
410 		mylabel_2 = new JLabel("Validate");
411 		mytoolBar.add(mylabel_2);
412 
413 		myProfileCombobox = new JComboBox();
414 		mytoolBar.add(myProfileCombobox);
415 		myProfileCombobox.setPreferredSize(new Dimension(200, 27));
416 		myProfileCombobox.setMinimumSize(new Dimension(200, 27));
417 		myProfileCombobox.addActionListener(new ActionListener() {
418 
419 			public void actionPerformed(ActionEvent e) {
420 				if (myHandlingProfileComboboxChange) {
421 					return;
422 				}
423 
424 				myHandlingProfileComboboxChange = true;
425 				try {
426 					if (myProfileCombobox.getSelectedIndex() == 0) {
427 						myMessage.setValidationContext(null);
428 					} else if (myProfileCombobox.getSelectedIndex() == 1) {
429 						myMessage.setValidationContext(new DefaultValidation());
430 					} else if (myProfileCombobox.getSelectedIndex() > 0) {
431 						ProfileGroup profile = myProfileComboboxModel.myProfileGroups.get(myProfileCombobox.getSelectedIndex());
432 						myMessage.setRuntimeProfile(profile);
433 
434 						// } else if (myProfileCombobox.getSelectedItem() ==
435 						// ProfileComboModel.APPLY_CONFORMANCE_PROFILE) {
436 						// IOkCancelCallback<Void> callback = new
437 						// IOkCancelCallback<Void>() {
438 						// public void ok(Void theArg) {
439 						// myProfileComboboxModel.update();
440 						// }
441 						//
442 						// public void cancel(Void theArg) {
443 						// myProfileCombobox.setSelectedIndex(0);
444 						// }
445 						// };
446 						// myController.chooseAndLoadConformanceProfileForMessage(myMessage,
447 						// callback);
448 					}
449 				} catch (ProfileException e2) {
450 					ourLog.error("Failed to load profile", e2);
451 				} finally {
452 					myHandlingProfileComboboxChange = false;
453 				}
454 			}
455 		});
456 		myProfileCombobox.setMaximumSize(new Dimension(300, 32767));
457 		myProfileCombobox.setModel(myProfileComboboxModel);
458 
459 		myhorizontalStrut_4 = Box.createHorizontalStrut(20);
460 		myhorizontalStrut_4.setPreferredSize(new Dimension(2, 0));
461 		myhorizontalStrut_4.setMinimumSize(new Dimension(2, 0));
462 		myhorizontalStrut_4.setMaximumSize(new Dimension(2, 32767));
463 		mytoolBar.add(myhorizontalStrut_4);
464 
465 		// mySendingPanel = new JPanel();
466 		// mySendingPanel.setBorder(null);
467 		// myTopTabBar.addTab("Sending", null, mySendingPanel, null);
468 		// mySendingPanel.setLayout(new BorderLayout(0, 0));
469 
470 		mySendingActivityTable = new ActivityTable();
471 		mySendingActivityTable.setController(myController);
472 		myTopTabBar.addTab("Sending", null, mySendingActivityTable, null);
473 
474 		// mySendingPanelScrollPanel = new JScrollPane();
475 		// mySendingPanelScrollPanel.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
476 		// mySendingPanelScrollPanel.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
477 		// mySendingPanelScrollPanel.setColumnHeaderView(mySendingActivityTable);
478 		//
479 		// mySendingPanel.add(mySendingPanelScrollPanel, BorderLayout.CENTER);
480 
481 		bottomPanel = new JPanel();
482 		bottomPanel.setPreferredSize(new Dimension(10, 20));
483 		bottomPanel.setMinimumSize(new Dimension(10, 20));
484 		add(bottomPanel, BorderLayout.SOUTH);
485 		GridBagLayout gbl_bottomPanel = new GridBagLayout();
486 		gbl_bottomPanel.columnWidths = new int[] { 98, 74, 0 };
487 		gbl_bottomPanel.rowHeights = new int[] { 16, 0 };
488 		gbl_bottomPanel.columnWeights = new double[] { 0.0, 1.0, Double.MIN_VALUE };
489 		gbl_bottomPanel.rowWeights = new double[] { 0.0, Double.MIN_VALUE };
490 		bottomPanel.setLayout(gbl_bottomPanel);
491 
492 		mylabel = new JLabel("Terser Path:");
493 		mylabel.setHorizontalTextPosition(SwingConstants.LEFT);
494 		mylabel.setHorizontalAlignment(SwingConstants.LEFT);
495 		GridBagConstraints gbc_label = new GridBagConstraints();
496 		gbc_label.fill = GridBagConstraints.VERTICAL;
497 		gbc_label.weighty = 1.0;
498 		gbc_label.anchor = GridBagConstraints.NORTHWEST;
499 		gbc_label.gridx = 0;
500 		gbc_label.gridy = 0;
501 		bottomPanel.add(mylabel, gbc_label);
502 
503 		myTerserPathTextField = new JLabel();
504 		myTerserPathTextField.setForeground(Color.BLUE);
505 		myTerserPathTextField.setFont(new Font("Lucida Console", Font.PLAIN, 13));
506 		myTerserPathTextField.setBorder(null);
507 		myTerserPathTextField.setBackground(SystemColor.control);
508 		myTerserPathTextField.addMouseListener(new MouseAdapter() {
509 			@Override
510 			public void mouseClicked(MouseEvent e) {
511 				if (StringUtils.isNotEmpty(myTerserPathTextField.getText())) {
512 					myTerserPathPopupMenu.show(myTerserPathTextField, 0, 0);
513 				}
514 			}
515 		});
516 
517 		GridBagConstraints gbc_TerserPathTextField = new GridBagConstraints();
518 		gbc_TerserPathTextField.weightx = 1.0;
519 		gbc_TerserPathTextField.fill = GridBagConstraints.HORIZONTAL;
520 		gbc_TerserPathTextField.gridx = 1;
521 		gbc_TerserPathTextField.gridy = 0;
522 		bottomPanel.add(myTerserPathTextField, gbc_TerserPathTextField);
523 
524 		initLocal();
525 
526 	}
527 
528 
529 	public void destroy() {
530 		myMessage.removePropertyChangeListener(Hl7V2MessageCollection.SOURCE_MESSAGE_PROPERTY, myMessageListeneer);
531 		myMessage.removePropertyChangeListener(Hl7V2MessageCollection.PROP_HIGHLITED_RANGE, myRangeListener);
532 		myMessage.removePropertyChangeListener(Hl7V2MessageCollection.SAVED_PROPERTY, myWindowTitleListener);
533 		myMessage.removePropertyChangeListener(Hl7V2MessageCollection.PROP_SAVE_FILENAME, myWindowTitleListener);
534 
535 		myTreePanel.destroy();
536 		myController.getOutboundConnectionList().addPropertyChangeListener(OutboundConnectionList.PROP_LIST, myOutboundConnectionsListener);
537 
538 		myTablesComboModel.destroy();
539 		unregisterProfileNamesListeners();
540 	}
541 
542 
543 	private void initLocal() {
544 
545 		myDocumentListener = new DocumentListener() {
546 
547 			public void changedUpdate(DocumentEvent theE) {
548 				ourLog.info("Document change: " + theE);
549 				handleChange(theE);
550 			}
551 
552 
553 			private void handleChange(DocumentEvent theE) {
554 				myDontRespondToSourceMessageChanges = true;
555 				try {
556 					long start = System.currentTimeMillis();
557 
558 					String newSource = myMessageEditor.getText();
559 					int changeStart = theE.getOffset();
560 					int changeEnd = changeStart + theE.getLength();
561 					myMessage.updateSourceMessage(newSource, changeStart, changeEnd);
562 
563 					ourLog.info("Handled document update in {} ms", System.currentTimeMillis() - start);
564 				} finally {
565 					myDontRespondToSourceMessageChanges = false;
566 				}
567 			}
568 
569 
570 			public void insertUpdate(DocumentEvent theE) {
571 				ourLog.info("Document insert: " + theE);
572 				handleChange(theE);
573 			}
574 
575 
576 			public void removeUpdate(DocumentEvent theE) {
577 				ourLog.info("Document removed: " + theE);
578 				handleChange(theE);
579 			}
580 		};
581 		myMessageEditor.getDocument().addDocumentListener(myDocumentListener);
582 
583 		myMessageEditor.addCaretListener(new CaretListener() {
584 
585 			public void caretUpdate(final CaretEvent theE) {
586 				removeMostHighlights();
587 				if (!myDisableCaretUpdateHandling) {
588 					myController.invokeInBackground(new Runnable() {
589 						public void run() {
590 							myMessage.setHighlitedPathBasedOnRange(new Range(theE.getDot(), theE.getMark()));
591 							myTreePanel.repaint();
592 						}});
593 				}
594 			}
595 		});
596 
597 		updateOutboundConnectionsBox();
598 		myOutboundConnectionsListener = new PropertyChangeListener() {
599 
600 			public void propertyChange(PropertyChangeEvent theEvt) {
601 				updateOutboundConnectionsBox();
602 			}
603 		};
604 		myController.getOutboundConnectionList().addPropertyChangeListener(OutboundConnectionList.PROP_LIST, myOutboundConnectionsListener);
605 
606 		myOutboundInterfaceCombo.addActionListener(new ActionListener() {
607 			public void actionPerformed(ActionEvent theE) {
608 				if (!myOutboundInterfaceComboModelIsUpdating) {
609 					updateSendButton();
610 				}
611 			}
612 
613 		});
614 
615 		JMenuItem copyMenuItem = new JMenuItem("Copy to Clipboard");
616 		copyMenuItem.addActionListener(new ActionListener() {
617 			public void actionPerformed(ActionEvent theE) {
618 				String selection = myTerserPathTextField.getText();
619 				StringSelection data = new StringSelection(selection);
620 				Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
621 				clipboard.setContents(data, data);
622 			}
623 		});
624 		myTerserPathPopupMenu.add(copyMenuItem);
625 
626 		myProfilesListener = new PropertyChangeListener() {
627 			public void propertyChange(PropertyChangeEvent theEvt) {
628 				myProfileComboboxModel.update();
629 				registerProfileNamesListeners();
630 			}
631 		};
632 		myController.getProfileFileList().addPropertyChangeListener(ProfileFileList.PROP_FILES, myProfilesListener);
633 		registerProfileNamesListeners();
634 
635 		myProfilesNamesListener = new PropertyChangeListener() {
636 			public void propertyChange(PropertyChangeEvent theEvt) {
637 				myProfileComboboxModel.update();
638 			}
639 		};
640 
641 	}
642 
643 
644 	private void registerProfileNamesListeners() {
645 		unregisterProfileNamesListeners();
646 		for (ProfileGroup next : myController.getProfileFileList().getProfiles()) {
647 			next.addPropertyChangeListener(ProfileGroup.PROP_NAME, myProfilesNamesListener);
648 		}
649 	}
650 
651 
652 	private void unregisterProfileNamesListeners() {
653 		for (ProfileGroup next : myController.getProfileFileList().getProfiles()) {
654 			next.removePropertyChangeListener(ProfileGroup.PROP_NAME, myProfilesNamesListener);
655 		}
656 	}
657 
658 
659 	private void updateSendButton() {
660 		String selected = (String) myOutboundInterfaceCombo.getSelectedItem();
661 		if (selected == null || selected == NO_CONNECTIONS) {
662 			mySendButton.setEnabled(false);
663 			if (myMessage != null) {
664 				myMessage.setLastSendToInterfaceId(null);
665 			}
666 			return;
667 		}
668 
669 		if (selected == CREATE_NEW_CONNECTION) {
670 			IOkCancelCallback<OutboundConnection> handler = new IOkCancelCallback<OutboundConnection>() {
671 				public void ok(OutboundConnection theArg) {
672 					myMessage.setLastSendToInterfaceId(theArg.getId());
673 					myOutboundInterfaceCombo.setSelectedIndex(myOutboundInterfaceComboModel.getSize() - 2);
674 				}
675 
676 
677 				public void cancel(OutboundConnection theArg) {
678 					myOutboundInterfaceCombo.setSelectedIndex(0);
679 				}
680 			};
681 			myController.addOutboundConnectionToSendTo(handler);
682 			return;
683 		}
684 
685 		if (myMessage != null) {
686 			int selectedIndex = myOutboundInterfaceCombo.getSelectedIndex();
687 			OutboundConnection connection = myController.getOutboundConnectionList().getConnections().get(selectedIndex);
688 			myMessage.setLastSendToInterfaceId(connection.getId());
689 		}
690 
691 		mySendButton.setEnabled(true);
692 	}
693 
694 
695 	/**
696 	 * @param theMessage
697 	 *            the message to set
698 	 */
699 	public void setMessage(Hl7V2MessageCollection theMessage) {
700 		Validate.isTrue(myMessage == null);
701 
702 		myMessage = theMessage;
703 
704 		myShowCombo.setModel(new ShowComboModel());
705 
706 		// Prepopulate the "send to interface" combo to the last value it had
707 		if (StringUtils.isNotBlank(myMessage.getLastSendToInterfaceId())) {
708 			for (int i = 0; i < myOutboundInterfaceComboModelShadow.size(); i++) {
709 				if (myOutboundInterfaceComboModelShadow.get(i).getId().equals(myMessage.getLastSendToInterfaceId())) {
710 					myOutboundInterfaceCombo.setSelectedIndex(i);
711 					break;
712 				}
713 			}
714 		}
715 
716 		updateEncodingButtons();
717 		myRdbtnEr7.addActionListener(new ActionListener() {
718 			public void actionPerformed(ActionEvent theE) {
719 				removeHighlights();
720 				myMessage.setEncoding(Hl7V2EncodingTypeEnum.ER_7);
721 			}
722 		});
723 		myRdbtnXml.addActionListener(new ActionListener() {
724 			public void actionPerformed(ActionEvent theE) {
725 				removeHighlights();
726 				myMessage.setEncoding(Hl7V2EncodingTypeEnum.XML);
727 			}
728 		});
729 
730 		try {
731 			myDisableCaretUpdateHandling = true;
732 			updateMessageEditor();
733 		} finally {
734 			myDisableCaretUpdateHandling = false;
735 		}
736 
737 		myMessageListeneer = new PropertyChangeListener() {
738 			public void propertyChange(PropertyChangeEvent theEvt) {
739 				if (myDontRespondToSourceMessageChanges) {
740 					return;
741 				}
742 				try {
743 					myDisableCaretUpdateHandling = true;
744 					updateMessageEditor();
745 				} finally {
746 					myDisableCaretUpdateHandling = false;
747 				}
748 			}
749 		};
750 		myMessage.addPropertyChangeListener(Hl7V2MessageCollection.SOURCE_MESSAGE_PROPERTY, myMessageListeneer);
751 
752 		mySelectedPathListener = new PropertyChangeListener() {
753 
754 			public void propertyChange(PropertyChangeEvent theEvt) {
755 				String path = myMessage.getHighlitedPath();
756 				if (path == null) {
757 					path = "";
758 				}
759 
760 				int index = path.indexOf('/');
761 				if (index > -1) {
762 					path = path.substring(index);
763 				}
764 
765 				myTerserPathTextField.setText(path);
766 			}
767 		};
768 		myMessage.addPropertyChangeListener(Hl7V2MessageCollection.PROP_HIGHLITED_PATH, mySelectedPathListener);
769 
770 		myTreePanel.setMessage(myMessage);
771 
772 		myRangeListener = new PropertyChangeListener() {
773 
774 			public void propertyChange(PropertyChangeEvent theEvt) {
775 				if (theEvt.getNewValue() == null || !myFollowToggle.isSelected()) {
776 					return;
777 				}
778 				Range range = (Range) theEvt.getNewValue();
779 
780 				// myMessageScrollPane.getHorizontalScrollBar().setValue(0);
781 
782 				// myMessageEditor.select(range.getStart(), range.getEnd());
783 				// myMessageEditor.setCaretPosition(range.getStart());
784 
785 				myMessageEditor.setCaretPosition(range.getStart());
786 				myMessageEditor.moveCaretPosition(range.getEnd());
787 
788 				myMessageEditor.setCaretPosition(range.getEnd());
789 				myMessageEditor.moveCaretPosition(range.getStart());
790 
791 				// myMessageEditor.grabFocus();
792 				myMessageEditor.repaint();
793 
794 				String substring = myMessage.getSourceMessage().substring(range.getStart(), range.getEnd());
795 				ourLog.info("Selected range set to " + range + " which is " + substring);
796 			}
797 		};
798 		myMessage.addPropertyChangeListener(Hl7V2MessageCollection.PROP_HIGHLITED_RANGE, myRangeListener);
799 
800 		myProfileComboboxModel.update();
801 
802 		// Window Title
803 		myWindowTitleListener = new PropertyChangeListener() {
804 			public void propertyChange(PropertyChangeEvent theEvt) {
805 				updateWindowTitle();
806 			}
807 		};
808 		myMessage.addPropertyChangeListener(Hl7V2MessageCollection.SAVED_PROPERTY, myWindowTitleListener);
809 		myMessage.addPropertyChangeListener(Hl7V2MessageCollection.PROP_SAVE_FILENAME, myWindowTitleListener);
810 		updateWindowTitle();
811 
812 		EventQueue.invokeLater(new Runnable() {
813 
814 			public void run() {
815 				myMessageEditor.setCaretPosition(0);
816 				myMessageEditor.grabFocus();
817 			}
818 		});
819 
820 	}
821 
822 
823 	private void removeHighlights() {
824 		Highlighter hilite = myMessageEditor.getHighlighter();
825 		Highlighter.Highlight[] hilites = hilite.getHighlights();
826 		for (int i = 0; i < hilites.length; i++) {
827 			hilite.removeHighlight(hilites[i]);
828 		}
829 	}
830 
831 
832 	// Removes all but the 2 most recent highlights - the last tag pair
833 	// selected.
834 	private void removeMostHighlights() {
835 		Highlighter hilite = myMessageEditor.getHighlighter();
836 		Highlighter.Highlight[] hilites = hilite.getHighlights();
837 		for (int i = 0; i < hilites.length - 2; i++) {
838 			hilite.removeHighlight(hilites[i]);
839 		}
840 	}
841 
842 
843 	private void updateWindowTitle() {
844 		StringBuilder b = new StringBuilder();
845 
846 		if (myMessage.isSaved() == false) {
847 			b.append("Unsaved");
848 		}
849 
850 		if (b.length() > 0) {
851 			b.append(" - ");
852 		}
853 		if (StringUtils.isNotBlank(myMessage.getSaveFileName())) {
854 			b.append(myMessage.getSaveFileName());
855 		} else {
856 			b.append("New File");
857 		}
858 
859 		setWindowTitle(b.toString());
860 	}
861 
862 
863 	private void updateEncodingButtons() {
864 		switch (myMessage.getEncoding()) {
865 			case XML:
866 				myRdbtnXml.setSelected(true);
867 				myRdbtnEr7.setSelected(false);
868 				break;
869 			case ER_7:
870 				myRdbtnXml.setSelected(false);
871 				myRdbtnEr7.setSelected(true);
872 		}
873 	}
874 
875 	
876 
877 	private void updateMessageEditor() {
878 
879 		final JScrollBar vsb = myMessageScrollPane.getVerticalScrollBar();
880 		int initialVerticalValue = vsb.getValue();
881 
882 		myMessageEditor.getDocument().removeDocumentListener(myDocumentListener);
883 
884 		String sourceMessage = myMessage.getSourceMessage();
885 
886 		if (myMessage.getEncoding() == Hl7V2EncodingTypeEnum.XML) {
887 			myMessageEditor.setContentType("text/xml");
888 		} else {
889 			myMessageEditor.setContentType("text/er7");
890 			sourceMessage = sourceMessage.replace('\r', '\n');
891 		}
892 
893 		myMessageEditor.setText(sourceMessage);
894 
895 		myMessageEditor.getDocument().addDocumentListener(myDocumentListener);
896 
897 		final int verticalValue = Math.min(initialVerticalValue, vsb.getMaximum());
898 
899 		SwingUtilities.invokeLater(new Runnable() {
900 			public void run() {
901 				// myMessageEditor.setFont(Prefs.getHl7EditorFont());
902 				vsb.setValue(verticalValue);
903 			}
904 		});
905 
906 	}
907 
908 
909 	private void updateOutboundConnectionsBox() {
910 		int currentSelection = myOutboundInterfaceCombo.getSelectedIndex();
911 
912 		List<OutboundConnection> conn = myController.getOutboundConnectionList().getConnections();
913 
914 		myOutboundInterfaceComboModelIsUpdating = true;
915 
916 		myOutboundInterfaceComboModel.removeAllElements();
917 		myOutboundInterfaceComboModelShadow = new ArrayList<OutboundConnection>();
918 		if (conn.isEmpty()) {
919 			myOutboundInterfaceComboModel.addElement(NO_CONNECTIONS);
920 			myOutboundInterfaceComboModelShadow.add(null);
921 		} else {
922 			for (OutboundConnection next : conn) {
923 				myOutboundInterfaceComboModel.addElement(next.getName());
924 				myOutboundInterfaceComboModelShadow.add(next);
925 			}
926 		}
927 
928 		myOutboundInterfaceComboModel.addElement(CREATE_NEW_CONNECTION);
929 		myOutboundInterfaceComboModelShadow.add(null);
930 
931 		if (currentSelection != -1 && currentSelection < myOutboundInterfaceComboModel.getSize()) {
932 			myOutboundInterfaceCombo.setSelectedIndex(currentSelection);
933 		} else {
934 			myOutboundInterfaceCombo.setSelectedIndex(0);
935 		}
936 
937 		myOutboundInterfaceComboModelIsUpdating = false;
938 
939 		updateSendButton();
940 	}
941 
942 	private class ProfileComboModel extends DefaultComboBoxModel {
943 
944 		// private static final String APPLY_CONFORMANCE_PROFILE =
945 		// "Apply Conformance Profile...";
946 		private ArrayList<ProfileGroup> myProfileGroups;
947 
948 
949 		public void update() {
950 			myHandlingProfileComboboxChange = true;
951 			try {
952 				super.removeAllElements();
953 				myProfileGroups = new ArrayList<ProfileGroup>();
954 
955 				addElement("No Profile/Validation");
956 				myProfileGroups.add(null);
957 
958 				addElement("Default Datatype Validation (HAPI)");
959 				myProfileGroups.add(null);
960 
961 				// ProfileGroup profile = myMessage.getRuntimeProfile();
962 				// if (profile != null) {
963 				// String name = "Conf Profile (" +
964 				// profile.getMessage().getMsgType() + "^" +
965 				// profile.getMessage().getEventType() + ")";
966 				// String profName = myMessage.getRuntimeProfile().getName();
967 				// if (StringUtils.isNotBlank(profName)) {
968 				// name = name + ":" + profName;
969 				// }
970 				//
971 				// addElement(name);
972 				// }
973 
974 				// addElement(APPLY_CONFORMANCE_PROFILE);
975 
976 				for (ProfileGroup nextProfile : myController.getProfileFileList().getProfiles()) {
977 					String nextString = "Profile Group: " + nextProfile.getName();
978 					addElement(nextString);
979 					myProfileGroups.add(nextProfile);
980 					if (myMessage.getRuntimeProfile() == nextProfile) {
981 						setSelectedItem(nextString);
982 					}
983 				}
984 
985 				if (myMessage.getValidationContext() instanceof DefaultValidation) {
986 					setSelectedItem(getElementAt(1));
987 				} else if (getSelectedItem() == null) {
988 					setSelectedItem(getElementAt(0));
989 				}
990 			} finally {
991 				myHandlingProfileComboboxChange = false;
992 			}
993 		}
994 	}
995 
996 	public class ShowComboModel extends DefaultComboBoxModel implements ActionListener {
997 		private static final String ALL = "All";
998 		private static final String ERRORS = "Errors";
999 		private static final String POPULATED = "Populated";
1000 		private static final String SUPPORTED = "Supported";
1001 
1002 
1003 		public ShowComboModel() {
1004 			addElement(POPULATED);
1005 			addElement(ALL);
1006 			addElement(ERRORS);
1007 			addElement(SUPPORTED);
1008 
1009 			switch (myMessage.getEditorShowMode()) {
1010 				case ALL:
1011 					setSelectedItem(ALL);
1012 					break;
1013 				case ERROR:
1014 					setSelectedItem(ERRORS);
1015 					break;
1016 				case POPULATED:
1017 					setSelectedItem(POPULATED);
1018 					break;
1019 				case SUPPORTED:
1020 					setSelectedItem(SUPPORTED);
1021 					break;
1022 			}
1023 
1024 			myShowCombo.addActionListener(this);
1025 		}
1026 
1027 
1028 		public void actionPerformed(ActionEvent theE) {
1029 			String value = (String) myShowCombo.getSelectedItem();
1030 
1031 			if (value == ALL) {
1032 				myTreePanel.setEditorShowModeAndUpdateAccordingly(ShowEnum.ALL);
1033 			} else if (value == ERRORS) {
1034 				myTreePanel.setEditorShowModeAndUpdateAccordingly(ShowEnum.ERROR);
1035 			} else if (value == SUPPORTED) {
1036 				myTreePanel.setEditorShowModeAndUpdateAccordingly(ShowEnum.SUPPORTED);
1037 			} else {
1038 				myTreePanel.setEditorShowModeAndUpdateAccordingly(ShowEnum.POPULATED);
1039 			}
1040 
1041 		}
1042 	}
1043 
1044 
1045 	private void activateSendingActivityTabForConnection(OutboundConnection theConnection) {
1046 		mySendingActivityTable.setConnection(theConnection, false);
1047 		myTopTabBar.setSelectedComponent(mySendingActivityTable);
1048 	}
1049 
1050 	public Frame getWindow() {
1051 		return myController.getWindow();
1052 	}
1053 
1054 }