1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 package ca.uhn.hl7v2.testpanel.ui.v2tree;
30
31 import java.awt.Color;
32 import java.awt.Component;
33 import java.awt.EventQueue;
34 import java.awt.Font;
35 import java.awt.event.KeyAdapter;
36 import java.awt.event.KeyEvent;
37 import java.beans.PropertyChangeEvent;
38 import java.beans.PropertyChangeListener;
39 import java.lang.reflect.InvocationTargetException;
40 import java.util.ArrayList;
41 import java.util.Collection;
42 import java.util.HashSet;
43 import java.util.List;
44 import java.util.Set;
45
46 import javax.swing.DefaultListSelectionModel;
47 import javax.swing.Icon;
48 import javax.swing.ImageIcon;
49 import javax.swing.JScrollPane;
50 import javax.swing.JTable;
51 import javax.swing.JViewport;
52 import javax.swing.ListSelectionModel;
53 import javax.swing.SwingUtilities;
54 import javax.swing.event.CellEditorListener;
55 import javax.swing.event.ChangeEvent;
56 import javax.swing.table.DefaultTableCellRenderer;
57 import javax.swing.table.TableModel;
58 import javax.swing.tree.AbstractLayoutCache;
59 import javax.swing.tree.DefaultMutableTreeNode;
60 import javax.swing.tree.DefaultTreeModel;
61 import javax.swing.tree.TreeNode;
62 import javax.swing.tree.TreePath;
63
64 import org.apache.commons.lang.StringUtils;
65 import org.apache.commons.lang.Validate;
66 import org.netbeans.swing.outline.DefaultOutlineModel;
67 import org.netbeans.swing.outline.Outline;
68 import org.netbeans.swing.outline.OutlineModel;
69 import org.netbeans.swing.outline.RenderDataProvider;
70 import org.netbeans.swing.outline.RowModel;
71 import org.slf4j.Logger;
72 import org.slf4j.LoggerFactory;
73
74 import ca.uhn.hl7v2.HL7Exception;
75 import ca.uhn.hl7v2.conf.ProfileException;
76 import ca.uhn.hl7v2.conf.check.DefaultValidator;
77 import ca.uhn.hl7v2.model.AbstractGroup;
78 import ca.uhn.hl7v2.model.Composite;
79 import ca.uhn.hl7v2.model.Group;
80 import ca.uhn.hl7v2.model.Message;
81 import ca.uhn.hl7v2.model.Primitive;
82 import ca.uhn.hl7v2.model.Segment;
83 import ca.uhn.hl7v2.model.Structure;
84 import ca.uhn.hl7v2.model.Type;
85 import ca.uhn.hl7v2.model.Varies;
86 import ca.uhn.hl7v2.model.primitive.AbstractNumericPrimitive;
87 import ca.uhn.hl7v2.model.primitive.ID;
88 import ca.uhn.hl7v2.model.primitive.IS;
89 import ca.uhn.hl7v2.parser.EncodingCharacters;
90 import ca.uhn.hl7v2.parser.PipeParser;
91 import ca.uhn.hl7v2.testpanel.controller.Controller;
92 import ca.uhn.hl7v2.testpanel.model.UnknownMessage;
93 import ca.uhn.hl7v2.testpanel.model.conf.ConformanceComposite;
94 import ca.uhn.hl7v2.testpanel.model.conf.ConformanceGroup;
95 import ca.uhn.hl7v2.testpanel.model.conf.ConformanceMessage;
96 import ca.uhn.hl7v2.testpanel.model.conf.ConformancePrimitive;
97 import ca.uhn.hl7v2.testpanel.model.conf.ConformanceSegment;
98 import ca.uhn.hl7v2.testpanel.model.conf.TableFile;
99 import ca.uhn.hl7v2.testpanel.model.msg.AbstractMessage;
100 import ca.uhn.hl7v2.testpanel.model.msg.Comment;
101 import ca.uhn.hl7v2.testpanel.model.msg.Hl7V2MessageBase;
102 import ca.uhn.hl7v2.testpanel.model.msg.Hl7V2MessageCollection;
103 import ca.uhn.hl7v2.testpanel.ui.IDestroyable;
104 import ca.uhn.hl7v2.testpanel.ui.ImageFactory;
105 import ca.uhn.hl7v2.testpanel.ui.ShowEnum;
106 import ca.uhn.hl7v2.testpanel.util.SegmentAndComponentPath;
107 import ca.uhn.hl7v2.util.StringUtil;
108 import ca.uhn.hl7v2.validation.PrimitiveTypeRule;
109 import ca.uhn.hl7v2.validation.impl.DefaultValidation;
110 import ca.uhn.hl7v2.validation.impl.ValidationContextImpl;
111
112
113
114
115
116
117
118
119 public class Hl7V2MessageTree extends Outline implements IDestroyable {
120 private static final DefaultValidationhtml#DefaultValidation">DefaultValidation ourDefaultValidation = new DefaultValidation();
121
122 private static final Logger ourLog = LoggerFactory.getLogger(Hl7V2MessageTree.class);
123 private static final String TABLE_NAMESPACE_HL7 = "HL7";
124 private static final String TBL = " ";
125 private Controller myController;
126 private boolean myCurrentlyEditing;
127 private PropertyChangeListener myHighlitedPathListener;
128 private PropertyChangeListener myMessageEncodingListener;
129 private Hl7V2MessageCollection myMessages;
130 private PropertyChangeListener myParsedMessagesListener;
131 private PipeParser myPipeParser;
132 private boolean myRespondingToManualRangeChange;
133 private DefaultValidator myRuntimeProfileValidator;
134 private boolean mySelectionHandlingDisabled;
135 private boolean myShouldOpenDefaultPaths = true;
136
137 private boolean myShowRep0 = true;
138
139 private TreeRowModel myTableModel;
140
141 private TreeNodeRoot myTop;
142
143 private DefaultTreeModel myTreeModel;
144
145 private ShowEnum myUnitTestShowMode;
146
147 private UpdaterThread myUpdaterThread;
148
149 private PropertyChangeListener myValidationContextListener;
150
151 private IWorkingListener myWorkingListener;
152
153
154 public Hl7V2MessageTree(Controller theController) {
155 addKeyListener(new KeyAdapter() {
156 @Override
157 public void keyPressed(KeyEvent e) {
158 handleKeyPress(e);
159 }
160 });
161
162 setFont(new Font("LUCIDA", Font.PLAIN, 9));
163
164 myController = theController;
165
166 myPipeParser = new PipeParser();
167 myPipeParser.setValidationContext(new ValidationContextImpl());
168
169 setRenderDataProvider(new TreeRenderDataProvider());
170
171 setShowGrid(true);
172 setGridColor(new Color(0.9f, 0.9f, 0.9f));
173 setRowHeight(16);
174
175 setRowSelectionAllowed(true);
176
177 setSelectionModel(new MySelectionModel());
178
179 ValueCellEditor valueCellEditor = new ValueCellEditor(getFont());
180 setDefaultEditor(String.class, valueCellEditor);
181
182 valueCellEditor.addCellEditorListener(new CellEditorListener() {
183
184 public void editingCanceled(ChangeEvent theE) {
185 ourLog.info("No longer editing");
186 myCurrentlyEditing = false;
187 }
188
189 public void editingStopped(ChangeEvent theE) {
190 ourLog.info("No longer editing");
191 myCurrentlyEditing = false;
192 }
193 });
194
195 myHighlitedPathListener = new PropertyChangeListener() {
196
197 public void propertyChange(PropertyChangeEvent theEvt) {
198 if (myController.isMessageEditorInFollowMode()) {
199 if (Hl7V2MessageTree.this.hasFocus() == false) {
200 synchronizeTreeWithHighlitedPath();
201 }
202 }
203 }
204
205 };
206
207 myParsedMessagesListener = new PropertyChangeListener() {
208
209 public void propertyChange(PropertyChangeEvent theEvt) {
210 myUpdaterThread.scheduleUpdate();
211 }
212 };
213
214 myValidationContextListener = new PropertyChangeListener() {
215
216 public void propertyChange(PropertyChangeEvent theEvt) {
217 myUpdaterThread.scheduleUpdate();
218 }
219 };
220
221 myMessageEncodingListener = new PropertyChangeListener() {
222
223 public void propertyChange(PropertyChangeEvent theEvt) {
224 myUpdaterThread.scheduleUpdate();
225 }
226 };
227
228 getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
229
230 myUpdaterThread = new UpdaterThread();
231 myUpdaterThread.start();
232 }
233
234 private int addChidrenExtra(String theParentName, Type thePrimitive, TreeNodeBase treeParent, Segment theSegment, List<Integer> theComponentPath, String theTerserPath, int cpIndex, int index) throws InterruptedException, InvocationTargetException {
235
236 for (int i = 0; i < thePrimitive.getExtraComponents().numComponents(); i++) {
237 Type nextType = thePrimitive.getExtraComponents().getComponent(i);
238 String nextParentName = theParentName + "-" + (i + 1);
239
240
241 String terserPath = theTerserPath + "-" + (i + 1);
242
243 index = addChildren(nextParentName, treeParent, false, false, null, i, nextType, theSegment, theComponentPath, index, terserPath);
244 }
245 return index;
246 }
247
248 void addChildren() throws InterruptedException, InvocationTargetException {
249 if (myMessages != null && myMessages.getRuntimeProfile() != null) {
250 myRuntimeProfileValidator = new DefaultValidator();
251 myRuntimeProfileValidator.setValidateChildren(false);
252 }
253
254 final Set<String> openPaths = getOpenPaths();
255
256 int selectedRow = getSelectedRow();
257 final String selectedPath = getPathAtRow(selectedRow);
258
259 if (myMessages != null) {
260 try {
261 addChildren(myMessages.getMessages(), myTop, "");
262 } catch (InterruptedException e) {
263 ourLog.info("Interrupted during an update loop, going to schedule another pass");
264 myUpdaterThread.scheduleUpdate();
265 } catch (InvocationTargetException e) {
266 ourLog.error("Failed up update message tree", e);
267 }
268
269 myTop.validate();
270
271 EventQueue.invokeLater(new Runnable() {
272 public void run() {
273 myTreeModel.nodeStructureChanged(myTop);
274 }
275 });
276
277 }
278
279 EventQueue.invokeLater(new Runnable() {
280 public void run() {
281 try {
282 mySelectionHandlingDisabled = true;
283 ourLog.debug("Open paths are: {}", openPaths);
284 if (openPaths.isEmpty() && myShouldOpenDefaultPaths) {
285 ourLog.info("Opening default paths");
286 final AbstractLayoutCache layout = ((OutlineModel) getModel()).getLayout();
287 for (int row = 0; row < layout.getRowCount(); row++) {
288 TreePath path = layout.getPathForRow(row);
289 Object component = path.getLastPathComponent();
290 if (component instanceof TreeNodeMessage || component instanceof TreeNodeUnknown || component instanceof TreeNodeGroup) {
291 expandPath(path);
292 }
293 }
294 myShouldOpenDefaultPaths = false;
295 } else {
296 ourLog.info("Opening pre-existing paths: {} and selected path: {}", openPaths, selectedPath);
297 expandPaths(openPaths, selectedPath);
298 }
299 } finally {
300 mySelectionHandlingDisabled = false;
301 }
302 }
303 });
304
305
306
307
308
309 }
310
311
312
313
314 void addChildren(Group messParent, TreeNodeBase treeParent, String theTerserPath) throws InterruptedException, InvocationTargetException {
315
316 String[] childNames = messParent.getNames();
317 int currChild = 0;
318 for (int i = 0; i < childNames.length; i++) {
319
320 try {
321 String nextName = childNames[i];
322
323 switch (getShowMode()) {
324 case ALL:
325 case ERROR:
326
327
328
329
330
331
332 messParent.get(nextName);
333 default:
334
335 }
336
337 Structure[] childReps = messParent.getAll(nextName);
338 boolean repeating = messParent.isRepeating(nextName);
339 boolean required = messParent.isRequired(nextName);
340
341 for (int j = 0; j < childReps.length; j++) {
342
343 TreeNodeBase newNode = null;
344 Structure nextStructure = childReps[j];
345 String groupName = nextStructure.getName();
346
347 String nextTerserPath = theTerserPath + "/" + groupName + (j > 0 ? ("(" + (j + 1) + ")") : "");
348
349 if (nextStructure instanceof Group) {
350
351 if (nextStructure instanceof ConformanceGroup) {
352 newNode = new TreeNodeGroupConf((ConformanceGroup) nextStructure, groupName, j, repeating, required, nextTerserPath);
353 } else {
354 newNode = new TreeNodeGroup((Group) nextStructure, groupName, j, repeating, required, nextTerserPath);
355 }
356
357 addChildren((Group) nextStructure, newNode, nextTerserPath);
358
359 newNode = insertOrReplaceWithExisting(treeParent, currChild, newNode);
360
361 } else if (nextStructure instanceof Segment) {
362
363 if (nextStructure instanceof ConformanceSegment) {
364 newNode = new TreeNodeSegmentConf((ConformanceSegment) nextStructure, groupName, j, repeating, required, nextTerserPath);
365 } else {
366 newNode = new TreeNodeSegment((Segment) nextStructure, groupName, j, repeating, required, nextTerserPath);
367 }
368
369 addChildren((Segment) nextStructure, newNode, nextTerserPath);
370
371 newNode = insertOrReplaceWithExisting(treeParent, currChild, newNode);
372
373 }
374
375 currChild++;
376
377 }
378 } catch (HL7Exception e) {
379 ourLog.error("Failed to add group to tree", e);
380 }
381 }
382 }
383
384 void addChildren(List<AbstractMessage<?>> theMessages, TreeNodeRoot theTop, String theTerserPath) throws InterruptedException, InvocationTargetException {
385 int index = 0;
386 for (AbstractMessage<?> abstractMessage : theMessages) {
387
388 if (abstractMessage instanceof Hl7V2MessageBase) {
389
390 Hl7V2MessageBase message = (Hl7V2MessageBase) abstractMessage;
391 TreeNodeMessage node;
392 if (message.getParsedMessage() instanceof ConformanceMessage) {
393 node = new TreeNodeMessageConf(index, message);
394 } else {
395 node = new TreeNodeMessage(index, message);
396 }
397 insertOrReplaceWithExisting(theTop, index, node);
398
399 addChildren(node.getMessage().getParsedMessage(), node, "");
400
401 } else if (abstractMessage instanceof UnknownMessage) {
402
403 UnknownMessage unknownMessage = (UnknownMessage) abstractMessage;
404 TreeNodeUnknown node = new TreeNodeUnknown(unknownMessage);
405 insertOrReplaceWithExisting(theTop, index, node);
406
407 String message = unknownMessage.getParsedMessage();
408 for (String line : message.split("(\\n|\\r)+")) {
409 line = StringUtil.chomp(line);
410 node.add(new TreeNodeUnknownLine(line));
411 }
412
413 } else if (abstractMessage instanceof Comment) {
414
415 TreeNodeComment node = new TreeNodeComment((Comment) abstractMessage);
416 insertOrReplaceWithExisting(theTop, index, node);
417
418 } else {
419
420 throw new IllegalStateException("Unknown type: " + abstractMessage.getClass());
421
422 }
423
424 index++;
425 }
426 }
427
428
429
430
431 void addChildren(Segment messParent, TreeNodeBase treeParent, String theTerserPath) throws InterruptedException, InvocationTargetException {
432
433 int n = messParent.numFields();
434 String[] names = messParent.getNames();
435 int index = 0;
436 for (int i = 1; i <= n; i++) {
437 try {
438
439 List<Integer> components = new ArrayList<Integer>();
440 components.add(Integer.valueOf(i));
441
442 switch (getShowMode()) {
443 case ALL:
444 case ERROR:
445
446
447
448
449
450
451 messParent.getField(i, 0);
452 default:
453
454 }
455
456 Type[] reps = messParent.getField(i);
457 boolean repeating = messParent.getMaxCardinality(i) != 1;
458 boolean required = messParent.isRequired(i);
459 String name = i <= names.length ? names[i - 1] : "Unknown";
460
461 for (int j = 0; j < reps.length; j++) {
462
463
464
465 Type type = reps[j];
466 String parentName = messParent.getName() + "-" + (i);
467
468 StringBuilder b = new StringBuilder();
469 b.append(theTerserPath);
470 b.append("-");
471 b.append((i));
472 if (repeating) {
473 b.append('(');
474 b.append(j + 1);
475 b.append(')');
476 }
477 String terserPath = b.toString();
478
479 index = addChildren(parentName, treeParent, repeating, required, name, j, type, messParent, components, index, terserPath);
480
481 }
482
483 } catch (HL7Exception e) {
484 ourLog.error("Failed to add child to tree", e);
485 }
486 }
487 }
488
489
490
491
492
493 void addChildren(String theParentName, Composite messParent, TreeNodeBase treeParent, Segment theSegment, List<Integer> theComponentPath, String theTerserPath) throws InterruptedException, InvocationTargetException {
494 Type[] components = messParent.getComponents();
495
496 int cpIndex = theComponentPath.size();
497 theComponentPath.add(null);
498
499 int index = 0;
500 for (int i = 0; i < components.length; i++) {
501 Type nextType = components[i];
502 String nextParentName = theParentName + "-" + (i + 1);
503
504 theComponentPath.set(cpIndex, Integer.valueOf(i + 1));
505 String terserPath = theTerserPath + "-" + (i + 1);
506
507 index = addChildren(nextParentName, treeParent, false, false, null, i, nextType, theSegment, theComponentPath, index, terserPath);
508 }
509
510 index = addChidrenExtra(theParentName, messParent, treeParent, theSegment, theComponentPath, theTerserPath, cpIndex, index);
511
512 theComponentPath.remove(cpIndex);
513
514 }
515
516 int addChildren(String theParentName, TreeNodeBase theTreeParent, boolean theRepeating, boolean theRequired, String theName, int theRepNum, Type theType, Segment theParent, List<Integer> theComponentNumbers, int theIndex, String theTerserPath) throws InterruptedException,
517 InvocationTargetException {
518 if (theType instanceof Varies) {
519 theType = ((Varies) theType).getData();
520 }
521
522 if (theType instanceof Composite) {
523 Composite composite = (Composite) theType;
524 TreeNodeType newNode;
525 if (composite instanceof ConformanceComposite) {
526 newNode = new TreeNodeCompositeConf(theParentName, composite, theName, theRepNum, theRepeating, theRequired, theParent, theComponentNumbers, theTerserPath);
527 } else {
528 newNode = new TreeNodeType(theParentName, composite, theName, theRepNum, theRepeating, theRequired, theParent, theComponentNumbers, theTerserPath);
529 }
530
531 addChildren(theParentName, composite, newNode, theParent, theComponentNumbers, theTerserPath);
532
533 newNode = (TreeNodeType) insertOrReplaceWithExisting(theTreeParent, theIndex, newNode);
534
535 } else {
536
537 Primitive primitive = (Primitive) theType;
538 TreeNodeType newNode;
539 if (primitive instanceof ConformancePrimitive) {
540 newNode = new TreeNodePrimitiveConf(theParentName, (ConformancePrimitive) primitive, theName, theRepNum, theRepeating, theRequired, theParent, theComponentNumbers, theTerserPath);
541 } else {
542 newNode = new TreeNodePrimitive(theParentName, primitive, theName, theRepNum, theRepeating, theRequired, theParent, theComponentNumbers, theTerserPath);
543 }
544
545 addChidrenExtra(theParentName, primitive, newNode, theParent, theComponentNumbers, theTerserPath, theComponentNumbers.size(), 0);
546
547 newNode = (TreeNodeType) insertOrReplaceWithExisting(theTreeParent, theIndex, newNode);
548
549 }
550
551 return theIndex + 1;
552 }
553
554
555 public void collapseAll() {
556 AbstractLayoutCache layout = ((OutlineModel) getModel()).getLayout();
557 for (int i = 0; i < layout.getRowCount(); i++) {
558 TreePath path = layout.getPathForRow(i);
559 collapsePath(path);
560 }
561 }
562
563 public void destroy() {
564 removeMessageListeners();
565
566 myTop.destroy();
567 myUpdaterThread.stopThread();
568 }
569
570 private void doSynchronizeTreeWithHighlitedPath() {
571 String highlitedPath = myMessages.getHighlitedPath();
572 if (highlitedPath == null) {
573 return;
574 }
575
576 final AbstractLayoutCache layout = ((OutlineModel) getModel()).getLayout();
577 int lastSegmentRow = -1;
578 int currentSegmentRow = -1;
579 int currentSelectedRow = -1;
580 int currentMessageIndex = -1;
581 for (int row = 0; row < layout.getRowCount(); row++) {
582
583 TreePath path = layout.getPathForRow(row);
584 Object component = path.getLastPathComponent();
585 if (component instanceof TreeNodeMessage) {
586 currentMessageIndex = ((TreeNodeMessage) component).getMessageIndex();
587 if (highlitedPath.startsWith(currentMessageIndex + "/")) {
588 expandPath(path);
589 } else {
590
591 }
592 continue;
593 }
594
595 if (component instanceof TreeNodeUnknown) {
596 continue;
597 }
598
599 if (component instanceof TreeNodeSegment) {
600 lastSegmentRow = row;
601 }
602
603 TreeNodeBase node = (TreeNodeBase) component;
604
605 String terserPath = (currentMessageIndex) + node.getTerserPath();
606 if (highlitedPath != null && highlitedPath.startsWith(terserPath) && !highlitedPath.startsWith(terserPath + "(")) {
607 expandPath(path);
608 if (highlitedPath.equals(terserPath)) {
609 currentSelectedRow = row;
610 getSelectionModel().setSelectionInterval(row, row);
611 currentSegmentRow = lastSegmentRow;
612 }
613 } else {
614
615 }
616
617 }
618
619
620
621 if (currentSegmentRow != -1 && currentSelectedRow != -1 && !myRespondingToManualRangeChange) {
622 JViewport viewPort = (JViewport) getParent();
623 final JScrollPane scrollPane = (JScrollPane) viewPort.getParent();
624
625 int tableHeaderHeight = getTableHeader().getHeight();
626
627 int numRowsVisible = ((scrollPane.getHeight() - tableHeaderHeight) / layout.getRowHeight()) - 1;
628 int segmentDelta = currentSelectedRow - currentSegmentRow;
629 if (segmentDelta > numRowsVisible) {
630 currentSegmentRow = currentSegmentRow + (segmentDelta - numRowsVisible);
631 }
632
633 final int scrollToRow = currentSegmentRow;
634 SwingUtilities.invokeLater(new Runnable() {
635 public void run() {
636 scrollPane.getVerticalScrollBar().setValue(layout.getRowHeight() * scrollToRow);
637 }
638 });
639
640 }
641 }
642
643 public void expandAll() {
644 AbstractLayoutCache layout = ((OutlineModel) getModel()).getLayout();
645 for (int i = 0; i < layout.getRowCount(); i++) {
646 TreePath path = layout.getPathForRow(i);
647 expandPath(path);
648 }
649 }
650
651 private void expandPaths(Set<String> theOpenPaths, String theSelectedPath) {
652 AbstractLayoutCache layout = ((OutlineModel) getModel()).getLayout();
653 int messageIndex = -1;
654 for (int i = 0; i < layout.getRowCount(); i++) {
655 TreePath path = layout.getPathForRow(i);
656
657 Object baseObj = path.getLastPathComponent();
658 String pathString = null;
659 if (baseObj instanceof TreeNodeMessage || baseObj instanceof TreeNodeUnknown) {
660 messageIndex++;
661 pathString = Integer.toString(messageIndex);
662 } else if (baseObj instanceof TreeNodeBase) {
663 pathString = (Integer.toString(messageIndex) + ((TreeNodeBase) baseObj).getTerserPath());
664 }
665
666 if (pathString != null) {
667 if (theOpenPaths.contains(pathString)) {
668 expandPath(path);
669 } else {
670 collapsePath(path);
671 }
672 if (pathString.equals(theSelectedPath)) {
673 getSelectionModel().setSelectionInterval(i, i);
674 }
675 }
676
677 }
678
679 }
680
681 private Set<String> getOpenPaths() {
682 Set<String> retVal = new HashSet<String>();
683
684 TableModel model = getModel();
685 AbstractLayoutCache layout = ((OutlineModel) model).getLayout();
686 int messageIndex = -1;
687 for (int i = 0; i < layout.getRowCount(); i++) {
688 TreePath path = layout.getPathForRow(i);
689
690 Object baseObj = path.getLastPathComponent();
691 if (baseObj instanceof TreeNodeMessage || baseObj instanceof TreeNodeUnknown) {
692
693 messageIndex++;
694
695 if (layout.getExpandedState(path)) {
696 retVal.add(Integer.toString(messageIndex));
697 }
698
699 } else {
700
701 baseObj = path.getPathComponent(path.getPathCount() - 2);
702 if (baseObj instanceof TreeNodeBase) {
703 retVal.add(Integer.toString(messageIndex) + ((TreeNodeBase) baseObj).getTerserPath());
704 }
705 }
706
707 }
708
709 return retVal;
710 }
711
712 private String getPathAtRow(int theRowIndex) {
713
714 AbstractLayoutCache layout = ((OutlineModel) getModel()).getLayout();
715 int messageIndex = -1;
716 for (int i = 0; i < layout.getRowCount(); i++) {
717 TreePath path = layout.getPathForRow(i);
718
719 Object baseObj = path.getLastPathComponent();
720 if (baseObj instanceof TreeNodeMessage || baseObj instanceof TreeNodeUnknown) {
721
722 messageIndex++;
723 if (i == theRowIndex) {
724 return Integer.toString(messageIndex);
725 }
726
727 } else {
728
729 if (i == theRowIndex && baseObj instanceof TreeNodeBase) {
730 return (Integer.toString(messageIndex) + ((TreeNodeBase) baseObj).getTerserPath());
731 }
732
733 }
734
735 }
736
737 return null;
738 }
739
740 private ShowEnum getShowMode() {
741 if (myUnitTestShowMode != null) {
742 return myUnitTestShowMode;
743 }
744 ShowEnum showMode = myMessages != null ? myMessages.getEditorShowMode() : ShowEnum.POPULATED;
745 return showMode;
746 }
747
748 private void handleKeyPress(KeyEvent theE) {
749 int row = getSelectedRow();
750 if (row == -1) {
751 return;
752 }
753
754 if (theE.getKeyCode() == KeyEvent.VK_ENTER || theE.getKeyCode() == KeyEvent.VK_F2) {
755 AbstractLayoutCache layout = ((OutlineModel) getModel()).getLayout();
756 TreePath path = layout.getPathForRow(row);
757 TreeNodeBase baseObj = (TreeNodeBase) path.getLastPathComponent();
758 if (myTableModel.isCellEditable(baseObj, TreeRowModel.COL_VALUE)) {
759 editCellAt(row, TreeRowModel.COL_VALUE + 1);
760 theE.consume();
761 }
762 }
763 }
764
765 private void handleNewSelectedIndex(int theNewIndex) {
766 if (mySelectionHandlingDisabled) {
767 return;
768 }
769 ourLog.info("New selection index: " + theNewIndex);
770
771 if (myCurrentlyEditing) {
772 ourLog.info("Not responding to new selection index because we are marked as editing right now");
773 return;
774 }
775
776 AbstractLayoutCache layout = ((OutlineModel) getModel()).getLayout();
777 TreePath path = layout.getPathForRow(theNewIndex);
778
779 DefaultMutableTreeNode lead = (DefaultMutableTreeNode) path.getLastPathComponent();
780 if (lead instanceof TreeNodeSegment) {
781 TreeNodeSegment segmentNode = (TreeNodeSegment) lead;
782 myMessages.setHighlitedRangeBasedOnSegment(segmentNode.getSegment());
783 } else if (lead instanceof TreeNodeGroup) {
784 TreeNodeGroup type = (TreeNodeGroup) lead;
785 try {
786 List<Segment> segments = type.getSegments();
787 myMessages.setHighlitedRangeBasedOnSegment(segments.toArray(new Segment[segments.size()]));
788 } catch (HL7Exception e) {
789 e.printStackTrace();
790 }
791 } else if (lead instanceof TreeNodeType) {
792 TreeNodeType type = (TreeNodeType) lead;
793 myMessages.setHighlitedRangeBasedOnField(type.getSegmentAndComponentPath());
794 } else {
795 myMessages.clearHighlight();
796 }
797
798 }
799
800 private void removeMessageListeners() {
801 if (myMessages != null) {
802 myMessages.removePropertyChangeListener(Hl7V2MessageCollection.PROP_HIGHLITED_PATH, myHighlitedPathListener);
803 myMessages.removePropertyChangeListener(Hl7V2MessageCollection.PARSED_MESSAGES_PROPERTY, myParsedMessagesListener);
804 myMessages.removePropertyChangeListener(Hl7V2MessageCollection.PROP_VALIDATIONCONTEXT_OR_PROFILE, myValidationContextListener);
805 myMessages.removePropertyChangeListener(Hl7V2MessageCollection.PROP_ENCODING, myMessageEncodingListener);
806 }
807 }
808
809 public void scheduleNewValidationPass() {
810 myUpdaterThread.scheduleUpdate();
811 }
812
813
814
815
816 @Override
817 public void setEditingRow(int theARow) {
818 if (theARow == -1) {
819 myCurrentlyEditing = false;
820 } else {
821 ourLog.info("Beginning editing row " + theARow);
822 myCurrentlyEditing = true;
823 }
824 super.setEditingRow(theARow);
825 }
826
827 public void setEditorShowModeAndUpdateAccordingly(ShowEnum theValue) {
828 if (myMessages != null && theValue != myMessages.getEditorShowMode()) {
829 myMessages.setEditorShowMode(theValue);
830 myUpdaterThread.scheduleUpdateNow();
831 }
832 }
833
834
835
836
837 public void setMessage(Hl7V2MessageCollection theMessage) {
838
839 removeMessageListeners();
840
841 myMessages = theMessage;
842
843 myMessages.addPropertyChangeListener(Hl7V2MessageCollection.PROP_HIGHLITED_PATH, myHighlitedPathListener);
844 myMessages.addPropertyChangeListener(Hl7V2MessageCollection.PARSED_MESSAGES_PROPERTY, myParsedMessagesListener);
845 myMessages.addPropertyChangeListener(Hl7V2MessageCollection.PROP_VALIDATIONCONTEXT_OR_PROFILE, myValidationContextListener);
846 myMessages.addPropertyChangeListener(Hl7V2MessageCollection.PROP_ENCODING, myMessageEncodingListener);
847
848 myTop = new TreeNodeRoot();
849 myTreeModel = new DefaultTreeModel(myTop, false);
850
851 myTableModel = new TreeRowModel(myTreeModel);
852 OutlineModel outlineModel = DefaultOutlineModel.createOutlineModel(myTreeModel, myTableModel);
853 setModel(outlineModel);
854
855 setRootVisible(false);
856
857 setDefaultRenderer(NodeValidationFailure.class, new ValidationTreeCellRenderer());
858
859
860 getColumnModel().getColumn(TreeRowModel.COL_VALUE + 1).setCellRenderer(new ValueCellRenderer(this));
861
862 updateUI();
863
864 myUpdaterThread.scheduleUpdateNow();
865
866 SwingUtilities.invokeLater(new Runnable() {
867
868 public void run() {
869 int width = getWidth() - 140;
870
871 getColumnModel().getColumn(0).setPreferredWidth(width / 2);
872
873
874 getColumnModel().getColumn(1).setPreferredWidth(35);
875 getColumnModel().getColumn(1).setMinWidth(35);
876 getColumnModel().getColumn(1).setMaxWidth(35);
877
878
879 getColumnModel().getColumn(2).setPreferredWidth(35);
880 getColumnModel().getColumn(2).setMinWidth(35);
881 getColumnModel().getColumn(2).setMaxWidth(35);
882
883
884 getColumnModel().getColumn(3).setPreferredWidth(50);
885 getColumnModel().getColumn(3).setMinWidth(50);
886 getColumnModel().getColumn(3).setMaxWidth(50);
887
888
889 getColumnModel().getColumn(4).setPreferredWidth(20);
890 getColumnModel().getColumn(4).setMinWidth(20);
891 getColumnModel().getColumn(4).setMaxWidth(20);
892
893 getColumnModel().getColumn(5).setPreferredWidth(width / 2);
894 }
895 });
896
897 }
898
899 void setMessageForUnitTest(Hl7V2MessageCollection theMessageModel) {
900 myMessages = theMessageModel;
901 }
902
903 void setRuntimeProfileValidator(DefaultValidator theRuntimeProfileValidator) {
904 myRuntimeProfileValidator = theRuntimeProfileValidator;
905 }
906
907 public void setUnitTestShowMode(ShowEnum theUnitTestShowMode) {
908 myUnitTestShowMode = theUnitTestShowMode;
909 myUpdaterThread.scheduleUpdateNow();
910 }
911
912
913
914
915
916 public void setWorkingListener(IWorkingListener theWorkingListener) {
917 myWorkingListener = theWorkingListener;
918 }
919
920 private void synchronizeTreeWithHighlitedPath() {
921 try {
922 mySelectionHandlingDisabled = true;
923 doSynchronizeTreeWithHighlitedPath();
924 } finally {
925 mySelectionHandlingDisabled = false;
926 }
927 }
928
929 private String xmlEncode(String theValue) {
930 if (theValue == null) {
931 return null;
932 }
933
934 StringBuilder b = new StringBuilder();
935 for (int i = 0; i < theValue.length(); i++) {
936 char nextChar = theValue.charAt(i);
937 switch (nextChar) {
938 case '\r':
939 case '\n':
940 b.append("<br>");
941 break;
942 case ' ':
943 b.append(" ");
944 break;
945 case '&':
946 b.append("&");
947 break;
948 case '<':
949 b.append("<");
950 break;
951 case '>':
952 b.append(">");
953 break;
954 default:
955 b.append(nextChar);
956 }
957 }
958 return b.toString();
959 }
960
961 private static TreeNodeBase insertOrReplaceWithExisting(final TreeNodeBase theTreeParent, final int theIndex, final TreeNodeBase theNewNode) throws InterruptedException, InvocationTargetException {
962
963 if (theTreeParent.getChildCount() <= theIndex) {
964 EventQueue.invokeAndWait(new Runnable() {
965 public void run() {
966 theTreeParent.insert(theNewNode, theIndex);
967 }
968 });
969 return theNewNode;
970 }
971
972
973
974
975
976 while (theTreeParent.getChildCount() > (theIndex)) {
977 TreeNode node = theTreeParent.getChildAt(theIndex);
978 if (node instanceof IDestroyable) {
979 ((IDestroyable) node).destroy();
980 }
981
982 EventQueue.invokeAndWait(new Runnable() {
983 public void run() {
984 theTreeParent.remove(theIndex);
985 }
986 });
987 if (theTreeParent.getChildCount() > (theIndex) && theTreeParent.getChildAt(theIndex).equals(theNewNode)) {
988 return (TreeNodeBase) theTreeParent.getChildAt(theIndex);
989 }
990 }
991
992 EventQueue.invokeAndWait(new Runnable() {
993 public void run() {
994 theTreeParent.insert(theNewNode, theIndex);
995 }
996 });
997
998 return theNewNode;
999 }
1000
1001
1002
1003
1004 public static String toHl7Table(int theTable) {
1005 return StringUtils.leftPad(Integer.toString(theTable), 4, '0');
1006 }
1007
1008 public interface IWorkingListener {
1009 void finishedWorking(String theStatus);
1010
1011 void startedWorking();
1012
1013 }
1014
1015
1016
1017
1018
1019 public class MySelectionModel extends DefaultListSelectionModel {
1020
1021 public void addSelectionInterval(int theIndex0, int theIndex1) {
1022
1023 }
1024
1025 public void removeSelectionInterval(int theIndex0, int theIndex1) {
1026
1027 }
1028
1029 public void setSelectionInterval(int theIndex0, int theIndex1) {
1030 myRespondingToManualRangeChange = true;
1031 try {
1032 handleNewSelectedIndex(theIndex0);
1033 super.setSelectionInterval(theIndex0, theIndex1);
1034 } finally {
1035 myRespondingToManualRangeChange = false;
1036 }
1037 }
1038
1039 }
1040
1041 private class NodeValidationFailure {
1042 private Icon myIcon;
1043 private String myMessage;
1044
1045 public NodeValidationFailure(Icon theIcon, String theMessage) {
1046 super();
1047 myIcon = theIcon;
1048 myMessage = theMessage;
1049 }
1050
1051
1052
1053
1054 public Icon getIcon() {
1055 return myIcon;
1056 }
1057
1058
1059
1060
1061 public String getMessage() {
1062 return myMessage;
1063 }
1064 }
1065
1066 public abstract class TreeNodeBase extends DefaultMutableTreeNode {
1067 protected static final String COLOR_REPNUM = "#808000";
1068
1069 private Boolean myContainError;
1070 private String myErrorDescription;
1071 private Boolean myHasContent;
1072 private final String myName;
1073 private final Boolean myRepeating;
1074 private final int myRepNum;
1075 private final Boolean myRequired;
1076 private final String myTerserPath;
1077 private List<HL7Exception> myValidationExceptions = new ArrayList<HL7Exception>();
1078
1079 public TreeNodeBase(Object theStructure) {
1080 super(theStructure);
1081 assert theStructure != null || this instanceof TreeNodeRoot;
1082
1083 myName = null;
1084 myTerserPath = null;
1085 myRepNum = 0;
1086 myRepeating = null;
1087 myRequired = null;
1088 }
1089
1090 public TreeNodeBase(Object theStructure, String theName, int theRepNum, Boolean theRepeating, Boolean theRequired, String theTerserPath) {
1091 super(theStructure);
1092 assert theStructure != null;
1093
1094 myName = theName;
1095 myRepNum = theRepNum;
1096 myRepeating = theRepeating;
1097 myRequired = theRequired;
1098 myTerserPath = theTerserPath;
1099 }
1100
1101 public void addValidationExceptions(List<HL7Exception> theProblems) {
1102 addValidationExceptions(theProblems.toArray(new HL7Exception[theProblems.size()]));
1103 }
1104
1105 public void addValidationExceptions(HL7Exception... theExceptions) {
1106 for (HL7Exception hl7Exception : theExceptions) {
1107 myValidationExceptions.add(hl7Exception);
1108 }
1109 }
1110
1111 public int countExceptions() {
1112 int retVal = 0;
1113
1114 for (int i = 0; i < getChildCount(); i++) {
1115 TreeNodeBase next = (TreeNodeBase) getChildAt(i);
1116 retVal += next.countExceptions();
1117 }
1118
1119 retVal += myValidationExceptions.size();
1120 return retVal;
1121 }
1122
1123
1124
1125
1126 public void doValidate() {
1127
1128 }
1129
1130 @Override
1131 public boolean equals(Object theObj) {
1132 if (theObj == null || !getClass().equals(theObj.getClass())) {
1133 return false;
1134 }
1135 return ((TreeNodeBase) theObj).getUserObject() == getUserObject();
1136 }
1137
1138 public String getDisplayName() {
1139 return null;
1140 }
1141
1142
1143
1144
1145 public String getErrorDescription() {
1146 if (myErrorDescription == null && myValidationExceptions.size() > 0) {
1147 StringBuilder b = new StringBuilder();
1148 b.append("<html><ul>");
1149 for (HL7Exception next : myValidationExceptions) {
1150 b.append("<li>");
1151 b.append(next.getMessage());
1152 }
1153 b.append("</ul></html>");
1154
1155 myErrorDescription = b.toString();
1156 }
1157 return myErrorDescription;
1158 }
1159
1160 public Integer getMaxLength() {
1161 return null;
1162 }
1163
1164 public Short getMaxReps() {
1165 if (isRepeating() == null) {
1166 return null;
1167 } else if (isRepeating()) {
1168 return -1;
1169 } else {
1170 return 1;
1171 }
1172 }
1173
1174 public Short getMinReps() {
1175 if (isRequired() == null) {
1176 return null;
1177 } else if (isRequired()) {
1178 return 1;
1179 } else {
1180 return 0;
1181 }
1182 }
1183
1184
1185
1186
1187 public String getName() {
1188 return myName;
1189 }
1190
1191 public StringBuilder getNodeText() {
1192 StringBuilder b = new StringBuilder();
1193
1194 b.append("<font color=\"" + getNodeTextColor() + "\">");
1195 b.append(myName);
1196 b.append("</font>");
1197
1198 if (myRepeating != null && myRepeating && (myShowRep0 || getRepNum() > 0)) {
1199 b.append("<font color=\"" + COLOR_REPNUM + "\">");
1200 b.append(" (rep");
1201 if (myRepNum > 0) {
1202 b.append(' ');
1203 b.append(myRepNum + 1);
1204 }
1205 b.append(")");
1206 b.append("</font>");
1207 }
1208
1209 if (StringUtils.isNotBlank(getDisplayName())) {
1210 b.append("<font color=\"#00A000\">");
1211 b.append(" - ");
1212 b.append(getDisplayName());
1213 b.append("</font>");
1214 }
1215
1216 return b;
1217 }
1218
1219 public String getNodeTextColor() {
1220 return "#000000";
1221 }
1222
1223 public String getPipeEncodedValue() {
1224 return null;
1225 }
1226
1227
1228
1229
1230 public int getRepNum() {
1231 return myRepNum;
1232 }
1233
1234
1235
1236
1237 public String getTerserPath() {
1238 return myTerserPath;
1239 }
1240
1241 @Override
1242 public int hashCode() {
1243 Object object = getUserObject();
1244 if (object != null) {
1245 return object.hashCode();
1246 } else {
1247 return super.hashCode();
1248 }
1249 }
1250
1251
1252
1253
1254 public boolean isContainError() {
1255 if (myContainError == null) {
1256 if (isHasContent() == false) {
1257 myContainError = false;
1258 } else if (getErrorDescription() != null) {
1259 myContainError = true;
1260 } else {
1261 for (int i = 0; i < getChildCount(); i++) {
1262 TreeNodeBase nextChild = (TreeNodeBase) getChildAt(i);
1263 if (nextChild.isHasContent() && nextChild.isContainError()) {
1264 myContainError = true;
1265 break;
1266 }
1267 }
1268 if (myContainError == null) {
1269 myContainError = false;
1270 }
1271 }
1272 }
1273 return myContainError;
1274 }
1275
1276 public Boolean isHasContent() {
1277 if (myHasContent == null) {
1278 for (int i = 0; i < getChildCount(); i++) {
1279 TreeNodeBase next = (TreeNodeBase) getChildAt(i);
1280 if (next.isHasContent() == Boolean.TRUE) {
1281 myHasContent = Boolean.TRUE;
1282 break;
1283 }
1284 }
1285
1286 if (myHasContent == null) {
1287 myHasContent = Boolean.FALSE;
1288 }
1289 }
1290 return myHasContent;
1291 }
1292
1293
1294
1295
1296 public Boolean isRepeating() {
1297 return myRepeating;
1298 }
1299
1300
1301
1302
1303 public Boolean isRequired() {
1304 return myRequired;
1305 }
1306
1307
1308
1309
1310 protected boolean isSupported() {
1311 return true;
1312 }
1313
1314
1315
1316
1317
1318 public void setErrorDescription(String theErrorDescription) {
1319 myErrorDescription = theErrorDescription;
1320 }
1321
1322 public final void validate() throws InterruptedException, InvocationTargetException {
1323 for (int i = 0; i < getChildCount(); i++) {
1324 TreeNodeBase next = (TreeNodeBase) getChildAt(i);
1325
1326 if (next.isHasContent()) {
1327 next.validate();
1328 }
1329
1330 ShowEnum showMode = myMessages.getEditorShowMode();
1331 if ((next.getErrorDescription() == null && showMode == ShowEnum.ERROR) || (next.isHasContent() == false && showMode == ShowEnum.POPULATED) || (next.isSupported() == false && next.getErrorDescription() == null && showMode == ShowEnum.SUPPORTED)) {
1332 final int index = i;
1333 EventQueue.invokeAndWait(new Runnable() {
1334 public void run() {
1335 remove(index);
1336 }
1337 });
1338 i--;
1339 continue;
1340 }
1341
1342 }
1343
1344 doValidate();
1345 }
1346 }
1347
1348 public class TreeNodeComment extends TreeNodeBase implements IDestroyable {
1349 private PropertyChangeListener myListener;
1350 private Comment myMessage;
1351
1352 public TreeNodeComment(Comment theMessage) {
1353 super(theMessage);
1354
1355 myMessage = theMessage;
1356
1357 myListener = new PropertyChangeListener() {
1358
1359 public void propertyChange(PropertyChangeEvent theEvt) {
1360 myTreeModel.nodeStructureChanged(myTop);
1361 }
1362 };
1363 myMessage.addPropertyChangeListener(UnknownMessage.PARSED_MESSAGE_PROPERTY, myListener);
1364
1365 }
1366
1367
1368
1369
1370 public void destroy() {
1371 myMessage.addPropertyChangeListener(UnknownMessage.PARSED_MESSAGE_PROPERTY, myListener);
1372 }
1373
1374 @Override
1375 public void doValidate() {
1376
1377 }
1378
1379 @Override
1380 public StringBuilder getNodeText() {
1381 StringBuilder retVal = new StringBuilder();
1382 retVal.append("<html><font color=\"#00FF00\">");
1383 retVal.append(myMessage.getSourceMessage());
1384 retVal.append("</font></html>");
1385 return retVal;
1386 }
1387
1388 }
1389
1390 public class TreeNodeCompositeConf extends TreeNodeType {
1391
1392 public TreeNodeCompositeConf(String theParentName, Type theComposite, String theGroupName, int theRepNum, boolean theRepeating, boolean theRequired, Segment theParent, List<Integer> theComponentPath, String theTerserPath) {
1393 super(theParentName, theComposite, theGroupName, theRepNum, theRepeating, theRequired, theParent, theComponentPath, theTerserPath);
1394 }
1395
1396 @Override
1397 public void doValidate() {
1398 EncodingCharacters enc;
1399 try {
1400 enc = EncodingCharacters.getInstance(getComposite().getMessage());
1401 } catch (HL7Exception e) {
1402 ourLog.error("Could not get encoding chars", e);
1403 enc = new EncodingCharacters('|', null);
1404 }
1405
1406 String encoded = PipeParser.encode(getComposite(), enc);
1407 List<HL7Exception> problems = myRuntimeProfileValidator.testType(getComposite(), getComposite().getConfDefinition(), encoded, "");
1408 addValidationExceptions(problems);
1409 }
1410
1411 public ConformanceComposite getComposite() {
1412 return (ConformanceComposite) super.getUserObject();
1413 }
1414
1415
1416
1417
1418 @Override
1419 protected String getDataTypeDescription() {
1420 String retVal = getComposite().getConfDefinition().getDatatype();
1421 return retVal;
1422 }
1423
1424 @Override
1425 public String getDisplayName() {
1426 return getComposite().getConfDefinition().getName();
1427 }
1428
1429 @Override
1430 public Integer getMaxLength() {
1431 return (int) getComposite().getConfDefinition().getLength();
1432 }
1433
1434 protected boolean isSupported() {
1435 return !"X".equals(getComposite().getConfDefinition().getUsage());
1436 }
1437
1438 }
1439
1440 public class TreeNodeGroup extends TreeNodeGroupBase {
1441
1442 public TreeNodeGroup(Group theGroup, String theGroupName, int theRepNum, boolean theRepeating, boolean theRequired, String theTerserPath) {
1443 super(theGroup, theGroupName, theRepNum, theRepeating, theRequired, theTerserPath);
1444 }
1445
1446 private void addToSegList(List<Segment> retVal, Group group) throws HL7Exception {
1447 for (String next : group.getNames()) {
1448 for (Structure nextStructure : group.getAll(next)) {
1449 if (nextStructure instanceof Segment) {
1450 retVal.add((Segment) nextStructure);
1451 } else {
1452 addToSegList(retVal, (Group) nextStructure);
1453 }
1454 }
1455 }
1456 }
1457
1458 public Group getGroup() {
1459 return (Group) getUserObject();
1460 }
1461
1462 @Override
1463 public String getNodeTextColor() {
1464 return "#404000";
1465 }
1466
1467 public List<Segment> getSegments() throws HL7Exception {
1468
1469 List<Segment> retVal = new ArrayList<Segment>();
1470
1471 Group group = getGroup();
1472 addToSegList(retVal, group);
1473
1474 return retVal;
1475 }
1476
1477 }
1478
1479 public class TreeNodeGroupBase extends TreeNodeBase {
1480 public TreeNodeGroupBase(Group theGroup, String theGroupName, int theRepNum, boolean theRepeating, boolean theRequired, String theTerserPath) {
1481 super(theGroup, theGroupName, theRepNum, theRepeating, theRequired, theTerserPath);
1482 }
1483
1484 public TreeNodeGroupBase(Hl7V2MessageBase theMessage) {
1485 super(theMessage);
1486 }
1487
1488 public int countPopulatedSegments() {
1489 int retVal = 0;
1490
1491 for (int i = 0; i < getChildCount(); i++) {
1492 TreeNode nextStructure = getChildAt(i);
1493 if (nextStructure instanceof TreeNodeSegment) {
1494 if (((TreeNodeSegment) nextStructure).isHasContent()) {
1495 retVal++;
1496 }
1497 } else if (nextStructure instanceof TreeNodeGroup) {
1498 retVal += ((TreeNodeGroup) nextStructure).countPopulatedSegments();
1499 }
1500 }
1501
1502 return retVal;
1503 }
1504
1505 }
1506
1507 public class TreeNodeGroupConf extends TreeNodeGroup {
1508
1509 public TreeNodeGroupConf(ConformanceGroup theGroup, String theGroupName, int theRepNum, boolean theRepeating, boolean theRequired, String theTerserPath) {
1510 super(theGroup, theGroupName, theRepNum, theRepeating, theRequired, theTerserPath);
1511 }
1512
1513 @Override
1514 public void doValidate() {
1515 try {
1516 List<HL7Exception> problems = myRuntimeProfileValidator.testGroup(getGroup(), getGroup().getConfDefinition(), "");
1517 addValidationExceptions(problems);
1518 } catch (ProfileException e) {
1519 addValidationExceptions(new HL7Exception(e));
1520 }
1521 }
1522
1523
1524
1525
1526 @Override
1527 public String getDisplayName() {
1528 return getGroup().getConfDefinition().getLongName();
1529 }
1530
1531 public ConformanceGroup getGroup() {
1532 return (ConformanceGroup) super.getGroup();
1533 }
1534
1535 protected boolean isSupported() {
1536 return !"X".equals(getGroup().getConfDefinition().getUsage());
1537 }
1538
1539 }
1540
1541 public class TreeNodeMessage extends TreeNodeGroupBase implements IDestroyable {
1542 private int myMessageIndex;
1543 private PropertyChangeListener myParsedMessageListener;
1544
1545 public TreeNodeMessage(int theMessageIndex, final Hl7V2MessageBase theMessage) {
1546 super(theMessage);
1547
1548 myMessageIndex = theMessageIndex;
1549
1550 myParsedMessageListener = new PropertyChangeListener() {
1551
1552 public void propertyChange(PropertyChangeEvent theEvt) {
1553 myUpdaterThread.scheduleUpdate();
1554 }
1555 };
1556 theMessage.addPropertyChangeListener(Hl7V2MessageBase.PARSED_MESSAGE_PROPERTY, myParsedMessageListener);
1557
1558 }
1559
1560 public void destroy() {
1561 ((Hl7V2MessageBase) getUserObject()).removePropertyChangeListener(Hl7V2MessageBase.PARSED_MESSAGE_PROPERTY, myParsedMessageListener);
1562 }
1563
1564 public Hl7V2MessageBase getMessage() {
1565 return (Hl7V2MessageBase) getUserObject();
1566 }
1567
1568
1569
1570
1571 public int getMessageIndex() {
1572 return myMessageIndex;
1573 }
1574
1575 public Message getParsedMessage() {
1576 return getMessage().getParsedMessage();
1577 }
1578 }
1579
1580 public class TreeNodeMessageConf extends TreeNodeMessage {
1581
1582 public TreeNodeMessageConf(int theIndex, Hl7V2MessageBase theMessage) {
1583 super(theIndex, theMessage);
1584 }
1585
1586 @Override
1587 public void doValidate() {
1588 try {
1589 HL7Exception[] problems = myRuntimeProfileValidator.validate(getParsedMessage(), getParsedMessage().getConfDefinition());
1590 addValidationExceptions(problems);
1591 } catch (ProfileException e) {
1592 addValidationExceptions(new HL7Exception(e));
1593 } catch (HL7Exception e) {
1594 addValidationExceptions(e);
1595 }
1596 }
1597
1598
1599
1600
1601 @Override
1602 public String getDisplayName() {
1603 return getParsedMessage().getConfDefinition().getDescription();
1604 }
1605
1606
1607
1608
1609 @Override
1610 public ConformanceMessage getParsedMessage() {
1611 return (ConformanceMessage) super.getParsedMessage();
1612 }
1613
1614 }
1615
1616 public class TreeNodePrimitive extends TreeNodeType {
1617
1618 public TreeNodePrimitive(String theParentName, Primitive theGroup, String theGroupName, int theRepNum, boolean theRepeating, boolean theRequired, Segment theParent, List<Integer> theComponentPath, String theTerserPath) {
1619 super(theParentName, theGroup, theGroupName, theRepNum, theRepeating, theRequired, theParent, theComponentPath, theTerserPath);
1620 }
1621
1622
1623
1624
1625 @Override
1626 public void doValidate() {
1627 super.doValidate();
1628
1629 Primitive primitive = getPrimitive();
1630 if (myMessages != null) {
1631 if (myMessages.getRuntimeProfile() != null) {
1632
1633
1634
1635 String version = primitive.getMessage().getVersion();
1636 String typeName = primitive.getName();
1637 Collection<PrimitiveTypeRule> rules = ourDefaultValidation.getPrimitiveRules(version, typeName, primitive);
1638 for (PrimitiveTypeRule rule : rules) {
1639 if (!rule.test(primitive.getValue())) {
1640 addValidationExceptions(new HL7Exception(rule.getDescription()));
1641 }
1642 }
1643
1644 } else if (myMessages.getValidationContext() != null) {
1645
1646 String version = primitive.getMessage().getVersion();
1647 String type = primitive.getName();
1648 Collection<PrimitiveTypeRule> rules = myMessages.getValidationContext().getPrimitiveRules(version, type, primitive);
1649 for (PrimitiveTypeRule primitiveTypeRule : rules) {
1650 boolean test = primitiveTypeRule.test(primitive.getValue());
1651 if (!test) {
1652
1653 addValidationExceptions(new HL7Exception(primitiveTypeRule.getDescription()));
1654 }
1655 }
1656
1657 }
1658
1659 }
1660
1661 }
1662
1663 @Override
1664 protected String getDataTypeDescription() {
1665 Primitive primitive = getPrimitive();
1666 if (primitive instanceof ID) {
1667 return super.getDataTypeDescription() + TBL + toHl7Table(((ID) primitive).getTable());
1668 }
1669 if (primitive instanceof IS) {
1670 return super.getDataTypeDescription() + TBL + toHl7Table(((IS) primitive).getTable());
1671 }
1672 return super.getDataTypeDescription();
1673 }
1674
1675 public Primitive getPrimitive() {
1676 return (Primitive) getUserObject();
1677 }
1678
1679 protected String getTable() {
1680 Primitive prim = getPrimitive();
1681 String namespace = TABLE_NAMESPACE_HL7;
1682 int retVal = 0;
1683 if (prim instanceof IS) {
1684 retVal = (((IS) prim).getTable());
1685 } else if (prim instanceof ID) {
1686 retVal = (((ID) prim).getTable());
1687 }
1688 return retVal > 0 ? namespace + toHl7Table(retVal) : null;
1689 }
1690
1691 @Override
1692 public Boolean isHasContent() {
1693 Primitive p = (Primitive) getUserObject();
1694 String value = p.getValue();
1695 boolean retVal = value != null && value.length() > 0;
1696 if (retVal) {
1697 return retVal;
1698 }
1699
1700 for (int i = 0; i < p.getExtraComponents().numComponents(); i++) {
1701 try {
1702 value = p.getExtraComponents().getComponent(i).encode();
1703 } catch (HL7Exception e) {
1704 return false;
1705 }
1706 retVal = value != null && value.length() > 0;
1707 if (retVal) {
1708 return retVal;
1709 }
1710 }
1711
1712 return false;
1713 }
1714
1715 }
1716
1717 public class TreeNodePrimitiveConf extends TreeNodePrimitive {
1718
1719 public TreeNodePrimitiveConf(String theParentName, ConformancePrimitive thePrimitive, String theGroupName, int theRepNum, boolean theRepeating, boolean theRequired, Segment theParent, List<Integer> theComponentPath, String theTerserPath) {
1720 super(theParentName, thePrimitive, theGroupName, theRepNum, theRepeating, theRequired, theParent, theComponentPath, theTerserPath);
1721
1722 }
1723
1724 @Override
1725 public void doValidate() {
1726 ConformancePrimitive primitive = getPrimitive();
1727 String tp = getTerserPath();
1728
1729 EncodingCharacters enc;
1730 try {
1731 enc = EncodingCharacters.getInstance(primitive.getMessage());
1732 } catch (HL7Exception e) {
1733 ourLog.error("Could not get encoding chars", e);
1734 enc = new EncodingCharacters('|', null);
1735 }
1736
1737 String encoded = PipeParser.encode(primitive, enc);
1738 if (tp.endsWith("MSH-1") || tp.endsWith("MSH-2")) {
1739 encoded = primitive.getValue();
1740 }
1741
1742 List<HL7Exception> problems = myRuntimeProfileValidator.testType(getPrimitive(), getPrimitive().getConfDefinition(), encoded, "");
1743 addValidationExceptions(problems);
1744
1745 if (myMessages.getRuntimeProfile() != null) {
1746 String table = getTable();
1747 if (table != null) {
1748
1749 ConformanceMessage msg = getPrimitive().getMessage();
1750 String tablesId = msg.getTablesId();
1751 if (StringUtils.isNotBlank(tablesId)) {
1752 TableFile tableFile = myController.getTableFileList().getTableFile(tablesId);
1753 if (tableFile != null) {
1754 if (tableFile.knowsCodes(table)) {
1755 String value = StringUtils.defaultString(primitive.getValue());
1756 if (!tableFile.isValidCode(table, value)) {
1757 addValidationExceptions(new HL7Exception("Not a valid value in table '" + table + "': " + value));
1758 }
1759 }
1760 }
1761 }
1762 }
1763 }
1764
1765 super.doValidate();
1766 }
1767
1768
1769
1770
1771 @Override
1772 protected String getDataTypeDescription() {
1773 String retVal = getPrimitive().getConfDefinition().getDatatype();
1774 String table = getPrimitive().getConfDefinition().getTable();
1775 if (StringUtils.isNotBlank(table)) {
1776 return retVal + TBL + table;
1777 } else {
1778 return retVal;
1779 }
1780 }
1781
1782 @Override
1783 public String getDisplayName() {
1784 return getPrimitive().getConfDefinition().getName();
1785 }
1786
1787 @Override
1788 public Integer getMaxLength() {
1789 return (int) getPrimitive().getConfDefinition().getLength();
1790 }
1791
1792 public ConformancePrimitive getPrimitive() {
1793 return (ConformancePrimitive) super.getPrimitive();
1794 }
1795
1796 @Override
1797 protected String getTable() {
1798 String retVal = getPrimitive().getConfDefinition().getTable();
1799 if (StringUtils.isBlank(retVal)) {
1800 return null;
1801 } else {
1802 if (AbstractNumericPrimitive.isInteger(retVal)) {
1803 return TABLE_NAMESPACE_HL7 + retVal;
1804 } else {
1805 return retVal;
1806 }
1807 }
1808 }
1809
1810 protected boolean isSupported() {
1811 return !"X".equals(getPrimitive().getConfDefinition().getUsage());
1812 }
1813
1814 }
1815
1816 public class TreeNodeRoot extends TreeNodeBase implements IDestroyable {
1817
1818 public TreeNodeRoot() {
1819 super(null);
1820 }
1821
1822 public int countMessages() {
1823 int retVal = 0;
1824 for (int i = 0; i < getChildCount(); i++) {
1825 if (getChildAt(i) instanceof TreeNodeMessage) {
1826 retVal++;
1827 }
1828 }
1829 return retVal;
1830 }
1831
1832 public void destroy() {
1833 for (int i = 0; i < getChildCount(); i++) {
1834 TreeNode next = getChildAt(i);
1835 if (next instanceof IDestroyable) {
1836 ((IDestroyable) next).destroy();
1837 }
1838 }
1839 }
1840
1841 }
1842
1843 public class TreeNodeSegment extends TreeNodeBase {
1844 public TreeNodeSegment(Segment theSegment, String theGroupName, int theRepNum, boolean theRepeating, boolean theRequired, String theTerserPath) {
1845 super(theSegment, theGroupName, theRepNum, theRepeating, theRequired, theTerserPath);
1846
1847 Validate.notNull(theTerserPath);
1848 Validate.isTrue(theTerserPath.startsWith("/"));
1849 }
1850
1851
1852
1853
1854 @Override
1855 public StringBuilder getNodeText() {
1856 StringBuilder retVal = super.getNodeText();
1857
1858 if (isNonStandard()) {
1859 retVal.append("<font color=\"#A0A000\">");
1860 retVal.append(" (non standard)");
1861 retVal.append("</font>");
1862 }
1863
1864 return retVal;
1865 }
1866
1867 @Override
1868 public String getNodeTextColor() {
1869 return "#006000";
1870 }
1871
1872
1873
1874
1875 @Override
1876 public String getPipeEncodedValue() {
1877 EncodingCharacters enc;
1878 try {
1879 enc = EncodingCharacters.getInstance(getSegment().getMessage());
1880 } catch (HL7Exception e) {
1881 ourLog.error("Could not get encoding chars", e);
1882 enc = new EncodingCharacters('|', null);
1883 }
1884 return PipeParser.encode(getSegment(), enc);
1885 }
1886
1887 public Segment getSegment() {
1888 return (Segment) getUserObject();
1889 }
1890
1891 @Override
1892 public Boolean isHasContent() {
1893 return getPipeEncodedValue().length() > 3;
1894 }
1895
1896 public boolean isNonStandard() {
1897 AbstractGroup parent = (AbstractGroup) getSegment().getParent();
1898 Set<String> nonStandardNames = parent.getNonStandardNames();
1899 String segmentName = getSegment().getName();
1900 return nonStandardNames.contains(segmentName);
1901 }
1902
1903 }
1904
1905 public class TreeNodeSegmentConf extends TreeNodeSegment {
1906 public TreeNodeSegmentConf(ConformanceSegment theSegment, String theGroupName, int theRepNum, boolean theRepeating, boolean theRequired, String theTerserPath) {
1907 super(theSegment, theGroupName, theRepNum, theRepeating, theRequired, theTerserPath);
1908 }
1909
1910 @Override
1911 public void doValidate() {
1912 try {
1913 List<HL7Exception> problems = myRuntimeProfileValidator.testSegment(getSegment(), getSegment().getConfDefinition(), "");
1914 addValidationExceptions(problems);
1915 } catch (ProfileException e) {
1916 addValidationExceptions(new HL7Exception(e));
1917 }
1918 }
1919
1920
1921
1922
1923 @Override
1924 public String getDisplayName() {
1925 return getSegment().getConfDefinition().getLongName();
1926 }
1927
1928
1929
1930
1931 @Override
1932 public Short getMaxReps() {
1933 return getSegment().getMaxReps();
1934 }
1935
1936
1937
1938
1939 @Override
1940 public Short getMinReps() {
1941 return getSegment().getMinReps();
1942 }
1943
1944 public ConformanceSegment getSegment() {
1945 return (ConformanceSegment) getUserObject();
1946 }
1947
1948 protected boolean isSupported() {
1949 return !"X".equals(getSegment().getConfDefinition().getUsage());
1950 }
1951 }
1952
1953 public class TreeNodeType extends TreeNodeBase {
1954 private ArrayList<Integer> myComponentPath;
1955 private String myParentName;
1956 private Segment mySegment;
1957
1958 public TreeNodeType(String theParentName, Type theGroup, String theGroupName, int theRepNum, boolean theRepeating, boolean theRequired, Segment theParent, List<Integer> theComponentPath, String theTerserPath) {
1959 super(theGroup, theGroupName, theRepNum, theRepeating, theRequired, theTerserPath);
1960
1961 Validate.notNull(theParent);
1962 Validate.notNull(theComponentPath);
1963 Validate.notEmpty(theComponentPath);
1964
1965 mySegment = theParent;
1966 myParentName = theParentName;
1967 myComponentPath = new ArrayList<Integer>(theComponentPath);
1968 }
1969
1970 protected String getDataTypeDescription() {
1971 return getType().getClass().getSimpleName();
1972 }
1973
1974 public StringBuilder getNodeText() {
1975 StringBuilder b = new StringBuilder();
1976
1977 b.append(myParentName);
1978
1979
1980
1981 if (isRepeating() && (myShowRep0 || getRepNum() > 0)) {
1982 b.append("<font color=\"" + COLOR_REPNUM + "\">");
1983 b.append(" (rep");
1984 if (getRepNum() > 0) {
1985 b.append(' ');
1986 b.append(getRepNum() + 1);
1987 }
1988 b.append(")");
1989 b.append("</font>");
1990 }
1991
1992 b.append("<font color=\"#00A000\">");
1993 if (StringUtils.isNotBlank(getDisplayName())) {
1994 b.append(" - ");
1995 b.append(getDisplayName());
1996 b.append(" ");
1997 }
1998 b.append(" (");
1999 b.append(getDataTypeDescription());
2000 b.append(")");
2001 b.append("</font>");
2002
2003 return b;
2004 }
2005
2006
2007
2008
2009 @Override
2010 public String getPipeEncodedValue() {
2011
2012 if (isMsh1orMsh2()) {
2013 return ((Primitive) getType()).getValue();
2014 }
2015
2016 EncodingCharacters enc;
2017 try {
2018 enc = EncodingCharacters.getInstance(getType().getMessage());
2019 } catch (HL7Exception e) {
2020 ourLog.error("Could not get encoding chars", e);
2021 enc = new EncodingCharacters('|', null);
2022 }
2023 return PipeParser.encode(getType(), enc);
2024 }
2025
2026 public SegmentAndComponentPath getSegmentAndComponentPath() {
2027 return new SegmentAndComponentPath(mySegment, myComponentPath, getRepNum() + 1);
2028 }
2029
2030 public Type getType() {
2031 return (Type) getUserObject();
2032 }
2033
2034 public boolean isMsh1orMsh2() {
2035 return "MSH-1".equals(myParentName) || "MSH-2".equals(myParentName);
2036 }
2037
2038 }
2039
2040 public class TreeNodeUnknown extends TreeNodeBase implements IDestroyable {
2041 private PropertyChangeListener myListener;
2042 private UnknownMessage myMessage;
2043
2044 public TreeNodeUnknown(UnknownMessage theMessage) {
2045 super(theMessage);
2046
2047 myMessage = theMessage;
2048
2049 myListener = new PropertyChangeListener() {
2050
2051 public void propertyChange(PropertyChangeEvent theEvt) {
2052 myTreeModel.nodeStructureChanged(myTop);
2053 }
2054 };
2055 myMessage.addPropertyChangeListener(UnknownMessage.PARSED_MESSAGE_PROPERTY, myListener);
2056
2057 }
2058
2059
2060
2061
2062 public void destroy() {
2063 myMessage.addPropertyChangeListener(UnknownMessage.PARSED_MESSAGE_PROPERTY, myListener);
2064 }
2065
2066 @Override
2067 public StringBuilder getNodeText() {
2068 StringBuilder retVal = new StringBuilder();
2069 retVal.append("<html><font color=\"#FF0000\">Unknown</font><font color=\"#A0A0A0\"> ");
2070
2071 int countLines = StringUtil.countLines(myMessage.getSourceMessage().trim());
2072 retVal.append(countLines);
2073 retVal.append(" Line");
2074
2075 if (countLines != 1) {
2076 retVal.append("s");
2077 }
2078
2079 retVal.append("</font></html>");
2080 return retVal;
2081 }
2082
2083 }
2084
2085 public class TreeNodeUnknownLine extends TreeNodeBase {
2086 public TreeNodeUnknownLine(Object theLine) {
2087 super(theLine);
2088 }
2089
2090 @Override
2091 public StringBuilder getNodeText() {
2092 StringBuilder retVal = new StringBuilder();
2093 retVal.append("<html><font color=\"#4040A0\">");
2094
2095 Object object = getUserObject();
2096 if (object != null) {
2097 retVal.append(xmlEncode(object.toString()));
2098 }
2099
2100 retVal.append("</font></html>");
2101 return retVal;
2102 }
2103
2104 }
2105
2106 private static class TreeRenderDataProvider implements RenderDataProvider {
2107
2108 private static final Color ourFgEmpty = new Color(0.5f, 0.5f, 0.5f);
2109 private static final Color ourFgGroup = new Color(0.4f, 0.4f, 0.0f);
2110 private static final Color ourFgNormal = new Color(0.0f, 0.0f, 0.0f);
2111 private static final Color ourFgSegment = new Color(0.0f, 0.0f, 0.0f);
2112
2113 public Color getBackground(Object theArg0) {
2114 return Color.white;
2115 }
2116
2117 public String getDisplayName(Object theObject) {
2118 if (theObject instanceof TreeNodeMessage) {
2119
2120 TreeNodeMessage tnm = (TreeNodeMessage) theObject;
2121 return (tnm.getMessage().getMessageDescription());
2122
2123 } else if (theObject instanceof TreeNodeBase) {
2124
2125 TreeNodeBase base = (TreeNodeBase) theObject;
2126 return (base.getNodeText().toString());
2127
2128 } else {
2129
2130 return "Unknown: " + theObject.getClass().getName();
2131
2132 }
2133 }
2134
2135 public Color getForeground(Object theArg0) {
2136 if (theArg0 instanceof TreeNodeBase) {
2137 if (Boolean.FALSE == ((TreeNodeBase) theArg0).isHasContent()) {
2138 return ourFgEmpty;
2139 }
2140 }
2141 if (theArg0 instanceof TreeNodeGroup) {
2142 return ourFgGroup;
2143 }
2144 if (theArg0 instanceof TreeNodeSegment) {
2145 return ourFgSegment;
2146 }
2147 return ourFgNormal;
2148 }
2149
2150 public Icon getIcon(Object theArg0) {
2151 if (theArg0 instanceof TreeNodeGroup) {
2152 return ImageFactory.getTreeBundle();
2153 } else if (theArg0 instanceof TreeNodeSegment) {
2154 return ImageFactory.getTreeLeaf();
2155 } else {
2156 return new ImageIcon();
2157 }
2158 }
2159
2160 public String getTooltipText(Object theArg0) {
2161 return null;
2162 }
2163
2164 public boolean isHtmlDisplayName(Object theArg0) {
2165 return true;
2166 }
2167
2168 }
2169
2170 private class TreeRowModel implements RowModel {
2171
2172 private static final int COL_LENGTH = 2;
2173 private static final int COL_MAX = 1;
2174 private static final int COL_MIN = 0;
2175 private static final int COL_VALIDATED = 3;
2176 private static final int COL_VALUE = 4;
2177
2178 private static final int NUM_COLS = 5;
2179
2180 public TreeRowModel(DefaultTreeModel theModel) {
2181 myTreeModel = theModel;
2182 }
2183
2184 public Class<?> getColumnClass(int theArg0) {
2185 if (theArg0 == COL_VALIDATED) {
2186 return NodeValidationFailure.class;
2187 }
2188 return String.class;
2189 }
2190
2191 public int getColumnCount() {
2192 return NUM_COLS;
2193 }
2194
2195 public String getColumnName(int theArg0) {
2196 switch (theArg0) {
2197 case COL_MIN:
2198 return "Min";
2199 case COL_MAX:
2200 return "Max";
2201 case COL_VALIDATED:
2202 return "";
2203 case COL_LENGTH:
2204 return "Length";
2205 case COL_VALUE:
2206 default:
2207 return "Value (Click to Edit)";
2208 }
2209 }
2210
2211 public Object getValueFor(Object theObject, int theCol) {
2212 TreeNodeBase obj = (TreeNodeBase) theObject;
2213 switch (theCol) {
2214 case COL_VALUE: {
2215 return obj;
2216 }
2217 case COL_MIN:
2218 if (obj.getMinReps() == null) {
2219 return null;
2220 } else {
2221 return obj.getMinReps();
2222 }
2223 case COL_MAX:
2224 if (obj.getMaxReps() == null) {
2225 return null;
2226 } else if (obj.getMaxReps() == -1) {
2227 return "*";
2228 } else {
2229 return obj.getMaxReps();
2230 }
2231 case COL_LENGTH:
2232 return obj.getMaxLength();
2233 case COL_VALIDATED:
2234
2235
2236
2237 if (obj.isContainError()) {
2238 if (obj.getErrorDescription() != null) {
2239 return new NodeValidationFailure(ImageFactory.getValFailed(), obj.getErrorDescription());
2240 } else {
2241 return new NodeValidationFailure(ImageFactory.getValFailedChild(), "Child element has validation failure");
2242 }
2243 } else {
2244 return new NodeValidationFailure(new ImageIcon(), "");
2245 }
2246 default:
2247 return "";
2248 }
2249 }
2250
2251 public boolean isCellEditable(Object theValue, int theColumn) {
2252 if (theColumn == COL_VALUE) {
2253 if (theValue instanceof TreeNodeSegment) {
2254 return true;
2255 }
2256 if (theValue instanceof TreeNodeType) {
2257 return true;
2258 }
2259 }
2260 return false;
2261 }
2262
2263 private void parse(Segment theSegment, String theNewValue) throws HL7Exception {
2264 EncodingCharacters enc;
2265 try {
2266 enc = EncodingCharacters.getInstance(theSegment.getMessage());
2267 } catch (HL7Exception e) {
2268 ourLog.error("Could not get encoding chars", e);
2269 enc = new EncodingCharacters('|', null);
2270 }
2271
2272 myPipeParser.parse(theSegment, theNewValue, enc);
2273 }
2274
2275 private void parse(Type theType, String theNewValue) throws HL7Exception {
2276 EncodingCharacters enc;
2277 try {
2278 enc = EncodingCharacters.getInstance(theType.getMessage());
2279 } catch (HL7Exception e) {
2280 ourLog.error("Could not get encoding chars", e);
2281 enc = new EncodingCharacters('|', null);
2282 }
2283
2284 theType.clear();
2285 myPipeParser.parse(theType, theNewValue, enc);
2286
2287 }
2288
2289 public void setValueFor(Object theObject, int theCol, Object theNewValue) {
2290 if (theCol != COL_VALUE) {
2291 return;
2292 }
2293
2294 Message msg = null;
2295 String newValue = (String) theNewValue;
2296 if (theObject instanceof TreeNodeSegment) {
2297 try {
2298 Segment segment = ((TreeNodeSegment) theObject).getSegment();
2299 parse(segment, newValue);
2300 msg = segment.getMessage();
2301 } catch (HL7Exception e) {
2302 ourLog.error("Could not set value: " + theNewValue, e);
2303 return;
2304 }
2305 } else if (theObject instanceof TreeNodeType) {
2306 try {
2307 TreeNodeType type = ((TreeNodeType) theObject);
2308
2309 if (!myController.validateNewValue(type.getTerserPath(), newValue)) {
2310 return;
2311 }
2312
2313 if (type.isMsh1orMsh2()) {
2314 ((Primitive) type.getType()).setValue(newValue);
2315 } else {
2316 parse(type.getType(), newValue);
2317 }
2318
2319 msg = type.getType().getMessage();
2320
2321 } catch (HL7Exception e) {
2322 ourLog.error("Could not set value: " + theNewValue, e);
2323 return;
2324 }
2325 } else {
2326 return;
2327 }
2328
2329 if (msg != null) {
2330
2331 TreeNodeBase base = (TreeNodeBase) theObject;
2332 while (!(base instanceof TreeNodeMessage)) {
2333 base = (TreeNodeBase) base.getParent();
2334 }
2335
2336 int messageIndex = ((TreeNodeMessage) base).getMessageIndex();
2337 myMessages.updateSourceMessageBasedOnParsedMessage(messageIndex, msg);
2338 }
2339
2340
2341
2342
2343
2344
2345 myUpdaterThread.scheduleUpdateNow();
2346
2347 }
2348
2349 }
2350
2351 private class UpdaterThread extends Thread {
2352 private long myNextUpdate = 0;
2353
2354 @Override
2355 public void run() {
2356
2357 while (myNextUpdate > -1) {
2358
2359 try {
2360 long sleepTime = myNextUpdate > 0 ? myNextUpdate - System.currentTimeMillis() : 5000;
2361 sleepTime = Math.max(0, sleepTime);
2362 sleepTime = Math.min(5000, sleepTime);
2363
2364 try {
2365 Thread.sleep(sleepTime);
2366 } catch (InterruptedException e) {
2367
2368 }
2369
2370 if (myNextUpdate > 0 && myNextUpdate <= System.currentTimeMillis()) {
2371 ourLog.info("Running an update of the Message Tree");
2372
2373 addChildren();
2374
2375 int messages = myTop.countMessages();
2376
2377 final StringBuilder b = new StringBuilder();
2378 b.append(messages > 0 ? messages : "No");
2379 b.append(" message");
2380 b.append(messages != 1 ? "s" : "");
2381 if (myMessages.isValidating()) {
2382 b.append(", ");
2383 int countExceptions = myTop.countExceptions();
2384 b.append(countExceptions > 0 ? countExceptions : "No");
2385 b.append(" problem");
2386 b.append(countExceptions != 1 ? "s" : "");
2387 }
2388
2389 if (myWorkingListener != null) {
2390 EventQueue.invokeAndWait(new Runnable() {
2391 public void run() {
2392 myWorkingListener.finishedWorking(b.toString());
2393 }
2394 });
2395 }
2396
2397 myNextUpdate = 0;
2398 }
2399
2400 } catch (InterruptedException e) {
2401
2402
2403
2404
2405
2406 } catch (Throwable e) {
2407
2408 ourLog.info("Exception caught during update loop", e);
2409 try {
2410 Thread.sleep(1000);
2411 } catch (InterruptedException e2) {
2412
2413 }
2414
2415 }
2416
2417 }
2418
2419 ourLog.info("Message Tree updater shutting down");
2420
2421 }
2422
2423 public void scheduleUpdate() {
2424 myNextUpdate = System.currentTimeMillis() + 2000;
2425 interrupt();
2426
2427 if (myWorkingListener != null) {
2428 EventQueue.invokeLater(new Runnable() {
2429 public void run() {
2430 myWorkingListener.startedWorking();
2431 }
2432 });
2433 }
2434
2435 }
2436
2437 public void scheduleUpdateNow() {
2438 myNextUpdate = System.currentTimeMillis();
2439 interrupt();
2440
2441 if (myWorkingListener != null) {
2442 EventQueue.invokeLater(new Runnable() {
2443 public void run() {
2444 myWorkingListener.startedWorking();
2445 }
2446 });
2447 }
2448
2449 }
2450
2451 public void stopThread() {
2452 myNextUpdate = -1;
2453 interrupt();
2454 }
2455
2456 }
2457
2458 private class ValidationTreeCellRenderer extends DefaultTableCellRenderer {
2459
2460 @Override
2461 public Component getTableCellRendererComponent(JTable theTable, Object theValue, boolean theIsSelected, boolean theHasFocus, int theRow, int theColumn) {
2462 Component tableCellRendererComponent = super.getTableCellRendererComponent(theTable, theValue, theIsSelected, theHasFocus, theRow, theColumn);
2463
2464 NodeValidationFailure vf = (NodeValidationFailure) theValue;
2465 setIcon(vf.getIcon());
2466 setToolTipText(vf.getMessage());
2467 setText("");
2468
2469 return tableCellRendererComponent;
2470 }
2471
2472 }
2473
2474 }