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