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;
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.event.ActionEvent;
33  import java.awt.event.ActionListener;
34  import java.beans.PropertyChangeEvent;
35  import java.beans.PropertyChangeListener;
36  import java.text.SimpleDateFormat;
37  import java.util.ArrayList;
38  import java.util.Collections;
39  import java.util.LinkedList;
40  import java.util.List;
41  
42  import javax.swing.Box;
43  import javax.swing.ImageIcon;
44  import javax.swing.JButton;
45  import javax.swing.JMenuItem;
46  import javax.swing.JPanel;
47  import javax.swing.JPopupMenu;
48  import javax.swing.JProgressBar;
49  import javax.swing.JScrollPane;
50  import javax.swing.JTable;
51  import javax.swing.JToolBar;
52  import javax.swing.ListSelectionModel;
53  import javax.swing.ScrollPaneConstants;
54  import javax.swing.SwingUtilities;
55  import javax.swing.event.ListSelectionEvent;
56  import javax.swing.event.ListSelectionListener;
57  import javax.swing.event.TableModelEvent;
58  import javax.swing.event.TableModelListener;
59  import javax.swing.table.TableModel;
60  
61  import org.slf4j.Logger;
62  import org.slf4j.LoggerFactory;
63  
64  import ca.uhn.hl7v2.testpanel.controller.Controller;
65  import ca.uhn.hl7v2.testpanel.model.ActivityBase;
66  import ca.uhn.hl7v2.testpanel.model.ActivityIncomingBytes;
67  import ca.uhn.hl7v2.testpanel.model.ActivityIncomingMessage;
68  import ca.uhn.hl7v2.testpanel.model.ActivityMessage;
69  import ca.uhn.hl7v2.testpanel.model.ActivityOutgoingBytes;
70  import ca.uhn.hl7v2.testpanel.model.ActivityOutgoingMessage;
71  import ca.uhn.hl7v2.testpanel.model.conn.AbstractConnection;
72  import ca.uhn.hl7v2.testpanel.model.conn.InboundConnection;
73  import ca.uhn.hl7v2.testpanel.ui.conn.JGraph;
74  import ca.uhn.hl7v2.testpanel.util.ISendProgressCallback;
75  
76  public class ActivityTable extends JPanel implements IDestroyable {
77  
78  	@SuppressWarnings("unused")
79  	private static final Logger ourLog = LoggerFactory.getLogger(ActivityTable.class);
80  
81  	private static final SimpleDateFormat ourTimestampFormat = new SimpleDateFormat("HH:mm:ss.SSS");
82  
83  	private JButton clearButton;
84  	private ActivityTableModel myActivityTableModel;
85  	private AbstractConnection myConnection;
86  	private Controller myController;
87  	private JMenuItem myEditAllButton;
88  	private JButton myEditButton;
89  	private JPopupMenu myEditMenu;
90  	private JMenuItem myEditSelectedButton;
91  	private boolean myInboundConnection;
92  	private PropertyChangeListener myRecentActivityListener;
93  	private JMenuItem mySaveAllButton;
94  	private JButton mySaveButton;
95  
96  	/**
97  	 * @wbp.nonvisual location=44,371
98  	 */
99  	private JPopupMenu mySaveMenu;
100 
101 	private JMenuItem mySaveSelectedButton;
102 	private JScrollPane myScrollPane;
103 	private JTable myTable;
104 	private ActivityDetailsCellRenderer myDetailsCellRenderer;
105 	private JProgressBar myProgressBar;
106 	private Component myhorizontalGlue;
107 	private JButton myStop;
108 
109 	protected boolean myTransmissionCancelled;
110 
111 	private JGraph mySendThroughputGraph;
112 
113 	public ActivityTable() {
114 		super(new BorderLayout());
115 		setBorder(null);
116 
117 		JToolBar toolBar = new JToolBar();
118 		toolBar.setRollover(true);
119 		toolBar.setFloatable(false);
120 		add(toolBar, BorderLayout.NORTH);
121 
122 		clearButton = new JButton("Clear");
123 		clearButton.addMouseListener(new HoverButtonMouseAdapter(clearButton));
124 		clearButton.setIcon(new ImageIcon(ActivityTable.class.getResource("/ca/uhn/hl7v2/testpanel/images/clear.png")));
125 		clearButton.setBorderPainted(false);
126 		clearButton.addActionListener(new ActionListener() {
127 
128 			public void actionPerformed(ActionEvent theE) {
129 				myConnection.clearRecentActivity();
130 			}
131 		});
132 		toolBar.add(clearButton);
133 
134 		mySaveButton = new JButton("Save");
135 		mySaveButton.addMouseListener(new HoverButtonMouseAdapter(mySaveButton));
136 		mySaveButton.setBorderPainted(false);
137 		mySaveButton.setEnabled(false);
138 		mySaveButton.setIcon(new ImageIcon(ActivityTable.class.getResource("/ca/uhn/hl7v2/testpanel/images/save.png")));
139 		mySaveButton.addActionListener(new ActionListener() {
140 			public void actionPerformed(ActionEvent e) {
141 				mySaveMenu.show(mySaveButton, mySaveButton.getX(), mySaveButton.getY() + mySaveButton.getHeight());
142 			}
143 		});
144 		toolBar.add(mySaveButton);
145 
146 		myEditButton = new JButton("Edit");
147 		myEditButton.setEnabled(false);
148 		myEditButton.setBorderPainted(false);
149 		myEditButton.addMouseListener(new HoverButtonMouseAdapter(myEditButton));
150 		myEditButton.setIcon(new ImageIcon(ActivityTable.class.getResource("/ca/uhn/hl7v2/testpanel/images/edit_one.png")));
151 		myEditButton.addActionListener(new ActionListener() {
152 			public void actionPerformed(ActionEvent e) {
153 				myEditMenu.show(myEditButton, myEditButton.getX(), myEditButton.getY() + myEditButton.getHeight());
154 			}
155 		});
156 		toolBar.add(myEditButton);
157 
158 		myhorizontalGlue = Box.createHorizontalGlue();
159 		toolBar.add(myhorizontalGlue);
160 
161 		mySendThroughputGraph = new JGraph();
162 		mySendThroughputGraph.setPreferredSize(new Dimension(200, 0));
163 		mySendThroughputGraph.setMinimumSize(new Dimension(200, 0));
164 		mySendThroughputGraph.setMaximumSize(new Dimension(200, 32767));
165 		toolBar.add(mySendThroughputGraph);
166 
167 		myStop = new JButton();
168 		myStop.addActionListener(new ActionListener() {
169 			public void actionPerformed(ActionEvent e) {
170 				myTransmissionCancelled = true;
171 				myStop.setEnabled(false);
172 			}
173 		});
174 		myStop.setEnabled(false);
175 		myStop.setBorderPainted(false);
176 		myStop.setIcon(new ImageIcon(ActivityTable.class.getResource("/ca/uhn/hl7v2/testpanel/images/stop.png")));
177 		myStop.addMouseListener(new HoverButtonMouseAdapter(myStop));
178 		toolBar.add(myStop);
179 
180 		myProgressBar = new JProgressBar();
181 		myProgressBar.setEnabled(false);
182 		myProgressBar.setMaximumSize(new Dimension(150, 20));
183 		myProgressBar.setMinimumSize(new Dimension(150, 20));
184 		myProgressBar.setPreferredSize(new Dimension(150, 20));
185 		toolBar.add(myProgressBar);
186 
187 		myScrollPane = new JScrollPane();
188 		myScrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
189 		add(myScrollPane, BorderLayout.CENTER);
190 
191 		myTable = new JTable();
192 		myTable.setGridColor(Color.LIGHT_GRAY);
193 		// myTable.setCellSelectionEnabled(true);
194 		// myTable.setRowSelectionAllowed(true);
195 		myTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
196 		myScrollPane.setViewportView(myTable);
197 
198 		myEditMenu = new JPopupMenu();
199 
200 		myEditSelectedButton = new JMenuItem("Edit Selected Message");
201 		myEditSelectedButton.setIcon(new ImageIcon(ActivityTable.class.getResource("/ca/uhn/hl7v2/testpanel/images/edit_one.png")));
202 		myEditSelectedButton.addActionListener(new ActionListener() {
203 			public void actionPerformed(ActionEvent theE) {
204 				ActivityMessage selected = (ActivityMessage) myActivityTableModel.getActivity(myTable.getSelectedRow());
205 				myController.editMessages(Collections.singletonList(selected));
206 			}
207 		});
208 		myEditMenu.add(myEditSelectedButton);
209 
210 		myEditAllButton = new JMenuItem("Edit All Messages");
211 		myEditAllButton.setIcon(new ImageIcon(ActivityTable.class.getResource("/ca/uhn/hl7v2/testpanel/images/edit_all.png")));
212 		myEditAllButton.addActionListener(new ActionListener() {
213 			public void actionPerformed(ActionEvent theE) {
214 				List<ActivityMessage> messages = myConnection.getRecentActivityEntriesOfType(ActivityMessage.class);
215 				myController.editMessages(messages);
216 			}
217 		});
218 		myEditMenu.add(myEditAllButton);
219 
220 		mySaveMenu = new JPopupMenu();
221 
222 		mySaveSelectedButton = new JMenuItem("Save Selected Message");
223 		mySaveSelectedButton.setIcon(new ImageIcon(ActivityTable.class.getResource("/ca/uhn/hl7v2/testpanel/images/save.png")));
224 		mySaveMenu.add(mySaveSelectedButton);
225 
226 		mySaveAllButton = new JMenuItem("Save All Messages");
227 		mySaveAllButton.setIcon(new ImageIcon(ActivityTable.class.getResource("/ca/uhn/hl7v2/testpanel/images/save_all.png")));
228 		mySaveMenu.add(mySaveAllButton);
229 
230 		myTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
231 			public void valueChanged(ListSelectionEvent theE) {
232 				updateUiBasedOnSelectedRow();
233 			}
234 		});
235 		updateUiBasedOnSelectedRow();
236 
237 		setProgressIndicatorsEnabled(false);
238 	}
239 
240 	/**
241 	 * @return the scrollPane
242 	 */
243 	public JScrollPane getScrollPane() {
244 		return myScrollPane;
245 	}
246 
247 	public void destroy() {
248 		removeListeners();
249 	}
250 
251 	/**
252 	 * @return the connection
253 	 */
254 	public AbstractConnection getConnection() {
255 		return myConnection;
256 	}
257 
258 	/**
259 	 * @return the inboundConnection
260 	 */
261 	public boolean isInboundConnection() {
262 		return myInboundConnection;
263 	}
264 
265 	public boolean isResponseAtRow(int theRow) {
266 		ActivityBase activity = myConnection.getRecentActivity().get(theRow);
267 		if ((activity instanceof ActivityOutgoingMessage || activity instanceof ActivityOutgoingBytes) && isInboundConnection()) {
268 			return true;
269 		}
270 
271 		if ((activity instanceof ActivityIncomingMessage || activity instanceof ActivityIncomingBytes) && !isInboundConnection()) {
272 			return true;
273 		}
274 
275 		return false;
276 	}
277 
278 	private void removeListeners() {
279 		if (myConnection != null) {
280 			myConnection.removePropertyChangeListener(AbstractConnection.RECENT_ACTIVITY_PROPERTY, myRecentActivityListener);
281 		}
282 	}
283 
284 	public void setConnection(AbstractConnection theConnection) {
285 		setConnection(theConnection, true);
286 	}
287 
288 	public void setConnection(AbstractConnection theConnection, boolean theIncludePreviousEvents) {
289 		removeListeners();
290 
291 		myConnection = theConnection;
292 		if (myConnection instanceof InboundConnection) {
293 			myInboundConnection = true;
294 		}
295 
296 		myActivityTableModel = new ActivityTableModel();
297 		myTable.setModel(myActivityTableModel);
298 
299 		myRecentActivityListener = new PropertyChangeListener() {
300 			public void propertyChange(PropertyChangeEvent theEvt) {
301 				SwingUtilities.invokeLater(new Runnable() {
302 					public void run() {
303 						myActivityTableModel.update();
304 						myDetailsCellRenderer.markScrollToBottom();
305 
306 					}
307 				});
308 			}
309 		};
310 		myConnection.addPropertyChangeListener(AbstractConnection.RECENT_ACTIVITY_PROPERTY, myRecentActivityListener);
311 		myActivityTableModel.update();
312 
313 		// JScrollBar vsb = myscrollPane.getVerticalScrollBar();
314 		// BoundedRangeModel vsbModel = new MyVerticalScrollbarModel();
315 		// vsb.setModel(vsbModel);
316 
317 		myTable.getColumnModel().getColumn(0).setCellRenderer(new ActivityCellRendererBase(this));
318 		myTable.getColumnModel().getColumn(1).setCellRenderer(new ActivityTypeCellRenderer(this, theConnection instanceof InboundConnection));
319 
320 		myDetailsCellRenderer = new ActivityDetailsCellRenderer(this);
321 		myTable.getColumnModel().getColumn(2).setCellRenderer(myDetailsCellRenderer);
322 
323 		final int timestampWidth = 100;
324 		myTable.getColumnModel().getColumn(0).setMaxWidth(timestampWidth);
325 		myTable.getColumnModel().getColumn(0).setMinWidth(timestampWidth);
326 		myTable.getColumnModel().getColumn(0).setPreferredWidth(timestampWidth);
327 
328 		final int activityWidth = 150;
329 		myTable.getColumnModel().getColumn(1).setMaxWidth(activityWidth);
330 		myTable.getColumnModel().getColumn(1).setMinWidth(activityWidth);
331 		myTable.getColumnModel().getColumn(1).setPreferredWidth(activityWidth);
332 
333 		int detailWidth = 5000;
334 		myTable.getColumnModel().getColumn(2).setMaxWidth(detailWidth);
335 		myTable.getColumnModel().getColumn(2).setMinWidth(detailWidth);
336 		myTable.getColumnModel().getColumn(2).setPreferredWidth(detailWidth);
337 	}
338 
339 	/**
340 	 * @param theController
341 	 *           the controller to set
342 	 */
343 	public void setController(Controller theController) {
344 		assert theController != null;
345 
346 		myController = theController;
347 	}
348 
349 	private void updateUiBasedOnSelectedRow() {
350 		boolean messageSelected = false;
351 		int selectedRow = myTable.getSelectedRow();
352 		if (selectedRow != -1) {
353 			Object activity = myActivityTableModel.getActivity(selectedRow);
354 			if (activity instanceof ActivityMessage) {
355 				messageSelected = true;
356 			}
357 		}
358 
359 		mySaveSelectedButton.setEnabled(messageSelected);
360 		myEditSelectedButton.setEnabled(messageSelected);
361 	}
362 
363 	class ActivityTableModel implements TableModel {
364 
365 		private List<TableModelListener> myTableListeners = new ArrayList<TableModelListener>();
366 
367 		public ActivityTableModel() {
368 		}
369 
370 		public void addTableModelListener(TableModelListener theL) {
371 			myTableListeners.add(theL);
372 		}
373 
374 		public Object getActivity(int theRowIndex) {
375 			return myConnection.getRecentActivity().get(theRowIndex);
376 		}
377 
378 		public Class<?> getColumnClass(int theColumnIndex) {
379 			return String.class;
380 		}
381 
382 		public int getColumnCount() {
383 			return 3;
384 		}
385 
386 		public String getColumnName(int theColumnIndex) {
387 			switch (theColumnIndex) {
388 			case 0:
389 				return "Timestamp";
390 			case 1:
391 				return "Activity";
392 			case 2:
393 				return "Details";
394 			default:
395 				throw new IllegalArgumentException(theColumnIndex + "");
396 			}
397 		}
398 
399 		public int getRowCount() {
400 			return myConnection.getRecentActivity().size();
401 		}
402 
403 		public Object getValueAt(int theRowIndex, int theColumnIndex) {
404 			ActivityBase activity = myConnection.getRecentActivity().get(theRowIndex);
405 
406 			switch (theColumnIndex) {
407 			case 0:
408 				return ourTimestampFormat.format(activity.getTimestamp());
409 			case 1:
410 			case 2:
411 			default:
412 				return activity;
413 			}
414 		}
415 
416 		public boolean isCellEditable(int theRowIndex, int theColumnIndex) {
417 			return false;
418 		}
419 
420 		public void removeTableModelListener(TableModelListener theL) {
421 			myTableListeners.remove(theL);
422 		}
423 
424 		public void setValueAt(Object theAValue, int theRowIndex, int theColumnIndex) {
425 			throw new UnsupportedOperationException();
426 		}
427 
428 		public void update() {
429 			if (mySaveButton.isEnabled() == false && myConnection.getRecentActivity().isEmpty() == false) {
430 				mySaveButton.setEnabled(true);
431 				myEditButton.setEnabled(true);
432 			}
433 			for (TableModelListener next : myTableListeners) {
434 				TableModelEvent event = new TableModelEvent(this);
435 				next.tableChanged(event);
436 			}
437 		}
438 
439 	}
440 
441 	public ActivityTableModel getTableModel() {
442 		return myActivityTableModel;
443 	}
444 
445 	// public class MyVerticalScrollbarModel extends DefaultBoundedRangeModel implements BoundedRangeModel {
446 	//
447 	// @Override
448 	// public void setRangeProperties(int theNewValue, int theNewExtent, int theNewMin, int theNewMax, boolean theAdjusting) {
449 	// super.setRangeProperties(theNewValue, theNewExtent, theNewMin, theNewMax, theAdjusting);
450 	//
451 	// int oldVal = getValue();
452 	// int newVal = getMaximum();
453 	// newVal = Math.min(newVal, Integer.MAX_VALUE - getExtent());
454 	//
455 	// newVal = Math.max(newVal, getMinimum());
456 	// if (newVal + getExtent() > getMaximum()) {
457 	// newVal = getMaximum() - getExtent();
458 	// }
459 	//
460 	// if (oldVal != newVal) {
461 	// ourLog.info("Changing scrollbar max from {} to {}", oldVal, newVal);
462 	// setValue(getMaximum());
463 	// }
464 	// }
465 	//
466 	// @Override
467 	// public void setMaximum(int theN) {
468 	// super.setMaximum(theN);
469 	//
470 	// int oldVal = getValue();
471 	// int newVal = getMaximum();
472 	//
473 	// if (oldVal != newVal) {
474 	// ourLog.info("Changing scrollbar max/max from {} to {}", oldVal, newVal);
475 	// setValue(getMaximum());
476 	// }
477 	// }
478 	//
479 	// public void setValue(int n) {
480 	// n = Math.min(n, Integer.MAX_VALUE - getExtent());
481 	//
482 	// int newValue = Math.max(n, getMinimum());
483 	// if (newValue + getExtent() > getMaximum()) {
484 	// newValue = getMaximum() - getExtent();
485 	// }
486 	//
487 	// ourLog.info("Changing scrollbarval to {}", newValue);
488 	//
489 	// super.setRangeProperties(newValue, getExtent(), getMinimum(), getMaximum(), getValueIsAdjusting());
490 	// }
491 	//
492 	// }
493 
494 	public ISendProgressCallback provideTransmissionCallback() {
495 		return new ISendProgressCallback() {
496 
497 			private LinkedList<Integer> myValues = new LinkedList<Integer>();
498 
499 			public void activityStopped() {
500 				setProgressIndicatorsEnabled(false);
501 			}
502 
503 			public void activityStarted() {
504 				setProgressIndicatorsEnabled(true);
505 				myTransmissionCancelled = false;
506 			}
507 
508 			public void progressUpdate(double theProgress) throws OperationCancelRequestedException {
509 				setProgress(theProgress);
510 				if (myTransmissionCancelled) {
511 					throw new OperationCancelRequestedException();
512 				}
513 			}
514 
515 			public void updateAvgThroughputPerSecond(int theThroughput) {
516 				myValues.add(theThroughput);
517 				while (myValues.size() > 100) {
518 					myValues.pop();
519 				}
520 				ourLog.info("Throughput values: {}", myValues);
521 				mySendThroughputGraph.setText(theThroughput + " msgs/sec");
522 				mySendThroughputGraph.setValues(myValues);
523 			}
524 
525 			public void updateAvgResponseTimeMillis(int theMillis) {
526 				// TODO Auto-generated method stub
527 
528 			}
529 		};
530 	}
531 
532 	public void setProgressIndicatorsEnabled(boolean theEnabled) {
533 		myStop.setEnabled(theEnabled);
534 		myStop.setVisible(theEnabled);
535 		myProgressBar.setEnabled(theEnabled);
536 		myProgressBar.setVisible(theEnabled);
537 	}
538 
539 	public void setProgress(double theProgress) {
540 		myProgressBar.setValue(Math.max(0, Math.min(100, (int) (theProgress * 100))));
541 	}
542 
543 }