View Javadoc
1   package org.opentrafficsim.imb.demo;
2   
3   import java.awt.BorderLayout;
4   import java.awt.Dimension;
5   import java.awt.EventQueue;
6   import java.awt.event.ActionEvent;
7   import java.awt.event.ActionListener;
8   import java.awt.event.KeyEvent;
9   import java.awt.event.KeyListener;
10  import java.util.Calendar;
11  import java.util.Date;
12  
13  import javax.swing.JButton;
14  import javax.swing.JFormattedTextField;
15  import javax.swing.JFrame;
16  import javax.swing.JLabel;
17  import javax.swing.JOptionPane;
18  import javax.swing.JPanel;
19  import javax.swing.JTextArea;
20  import javax.swing.JTextField;
21  import javax.swing.SwingUtilities;
22  
23  import nl.tno.imb.TByteBuffer;
24  import nl.tno.imb.TConnection;
25  import nl.tno.imb.TEventEntry;
26  
27  /**
28   * <p>
29   * Copyright (c) 2013-2016 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
30   * BSD-style license. See <a href="http://opentrafficsim.org/docs/current/license.html">OpenTrafficSim License</a>.
31   * <p>
32   * @version $Revision$, $LastChangedDate$, by $Author$, initial version Aug 19, 2016 <br>
33   * @author TNO
34   * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
35   * @author Walter Lohman
36   */
37  public class IMBChat extends JFrame
38  {
39  
40      /** */
41      private static final long serialVersionUID = 1L;
42  
43      /** Name of this chat user. */
44      private JTextField editName;
45  
46      /** IMB Federation. */
47      private JTextField editFederation;
48  
49      /** Message the the user is typing. */
50      private JTextField editMessage;
51  
52      /** Messages that have been exchanged. */
53      private JTextArea messages;
54  
55      /** Initiate connection to the IMB hub. */
56      JButton btnConnect;
57  
58      /** Connection to the IMB hub. */
59      private static TConnection connection = null;
60  
61      /** Message channel. */
62      private static TEventEntry chatMessageEvent = null;
63  
64      /**
65       * Convert a time.
66       * @param comTime double; the time in days since windows epoch
67       * @return Date
68       */
69      static public Date convertWindowsTimeToDate(double comTime)
70      {
71          return new Date(convertWindowsTimeToMilliseconds(comTime));
72      }
73  
74      /**
75       * Convert a time.
76       * @param comTime double; the time in days since windows epoch
77       * @return double; java time in milliseconds
78       */
79      static public long convertWindowsTimeToMilliseconds(double comTime)
80      {
81          long result = 0;
82  
83          comTime = comTime - 25569D;
84          Calendar cal = Calendar.getInstance();
85          result = Math.round(86400000L * comTime) - cal.get(Calendar.ZONE_OFFSET);
86          cal.setTime(new Date(result));
87          result -= cal.get(Calendar.DST_OFFSET);
88  
89          return result;
90      }
91  
92      /**
93       * Convert a Date to windows time.
94       * @param javaDate Date; the date to convert
95       * @return double; time in milliseconds
96       */
97      static public double convertDateToWindowsTime(Date javaDate)
98      {
99          if (javaDate == null)
100         {
101             throw new IllegalArgumentException("cannot convert null to windows time");
102         }
103         return convertMillisecondsToWindowsTime(javaDate.getTime());
104     }
105 
106     /**
107      * Convert a java time in milliseconds to windows time
108      * @param milliseconds long; the java time in milliseconds
109      * @return double; time in days since windows epoch
110      */
111     static public double convertMillisecondsToWindowsTime(long milliseconds)
112     {
113         double result = 0.0;
114 
115         Calendar cal = Calendar.getInstance();
116         cal.setTimeInMillis(milliseconds);
117         milliseconds += (cal.get(Calendar.ZONE_OFFSET) + cal.get(Calendar.DST_OFFSET)); // add GMT offset
118         result = (milliseconds / 86400000D) + 25569D;
119 
120         return result;
121     }
122 
123     /**
124      * Add received message to the message received box
125      * @param aDateTime Date; when was the message sent
126      * @param aName String; name of sender
127      * @param aMessage String; the message that was sent
128      */
129     void AddMessage(final Date aDateTime, final String aName, final String aMessage)
130     {
131         final JTextArea ta = this.messages;
132         SwingUtilities.invokeLater(new Runnable()
133         {
134             @Override
135             public void run()
136             {
137                 ta.setText(aDateTime.toString() + " " + aName + ": " + aMessage);
138             }
139 
140         });
141     }
142 
143     /**
144      * Are we currently connected to an IMB server?
145      * @return boolean
146      */
147     private boolean getConnected()
148     {
149         if (connection != null)
150             return connection.isConnected();
151         else
152             return false;
153     }
154 
155     /**
156      * Connect to the hub.
157      */
158     void Connect()
159     {
160         String server = "localhost";
161         int port = 4000;
162         connection = new TConnection(server, port, this.editName.getText(), 1, this.editFederation.getText());
163         // TODO: connection.onDisconnect
164         // connection.onDisconnect = new TConnection.TOnDisconnect()
165         // {
166         // @Override
167         // public void dispatch(TConnection aConnection)
168         // {
169         // // dispatch on display thread
170         // Display.getDefault().syncExec(new Runnable()
171         // {
172         // public void run()
173         // {
174         // chatMainForm.this.btnConnect.setText("Connect");
175         // }
176         // });
177         // }
178         // };
179         chatMessageEvent = connection.subscribe("Chat.Message");
180         chatMessageEvent.onNormalEvent = new TEventEntry.TOnNormalEvent()
181         {
182             @Override
183             public void dispatch(TEventEntry aEvent, TByteBuffer aPayload)
184             {
185                 // decode message
186                 double datetime = aPayload.readDouble();
187                 final String name = aPayload.readString();
188                 final String message = aPayload.readString();
189                 final Date javaDateTime = convertWindowsTimeToDate(datetime);
190                 // dispatch on display thread
191 
192                 // show received message
193                 AddMessage(javaDateTime, name, message);
194             }
195         };
196         // TODO: chatMessageEvent.OnNormalEvent
197         if (getConnected())
198             this.btnConnect.setText("Disconnect");
199         else
200             // ShowMessage("## Could not connect to hub " + aServerURI);
201             // java.awt.Dialog.
202             JOptionPane.showMessageDialog(null, "## Could not connect to hub ");
203     }
204 
205     /**
206      * Close the connection to the IMB hub.
207      */
208     void Disconnect()
209     {
210         if (getConnected())
211         {
212             connection.close();
213             this.btnConnect.setText("Connect");
214         }
215     }
216 
217     /**
218      * Send the message in the editMessage buffer to the IMB hub and clear the editMessage buffer.
219      */
220     void Send()
221     {
222         Date javaDateTime;
223         double datetime;
224         String name;
225         String message;
226         TByteBuffer payload;
227 
228         // send message
229         javaDateTime = new Date();
230         datetime = convertDateToWindowsTime(javaDateTime);
231         name = this.editName.getText();
232         message = this.editMessage.getText();
233         // encode message
234         payload = new TByteBuffer();
235         payload.prepare(datetime);
236         payload.prepare(name);
237         payload.prepare(message);
238         payload.prepareApply();
239         payload.qWrite(datetime);
240         payload.qWrite(name);
241         payload.qWrite(message);
242         chatMessageEvent.signalEvent(TEventEntry.EK_NORMAL_EVENT, payload.getBuffer());
243         // show our own message
244         AddMessage(javaDateTime, "me", message);
245         // clear previous message text
246         this.editMessage.setText("");
247     }
248 
249     /**
250      * Start up the application.
251      * @param args String[] args for main - should be empty
252      */
253     public static void main(String[] args)
254     {
255         try
256         {
257             EventQueue.invokeAndWait(new Runnable()
258             {
259 
260                 public void run()
261                 {
262                     try
263                     {
264                         new IMBChat();
265                     }
266                     catch (Exception e)
267                     {
268                         e.printStackTrace();
269                     }
270                 }
271 
272             });
273         }
274         catch (Exception e)
275         {
276             e.printStackTrace();
277         }
278     }
279 
280     /**
281      * Create the window.
282      */
283     public IMBChat()
284     {
285         this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
286         addWindowListener(new java.awt.event.WindowAdapter()
287         {
288             @Override
289             public void windowClosing(java.awt.event.WindowEvent windowEvent)
290             {
291                 Disconnect();
292             }
293         });
294         setPreferredSize(new Dimension(693, 443));
295         setTitle("Chat - Java");
296         JPanel mainPanel = new JPanel(new BorderLayout());
297         getContentPane().add(mainPanel);
298 
299         JPanel topPanel = new JPanel(new BorderLayout());
300         mainPanel.add(topPanel, BorderLayout.NORTH);
301         JPanel namePanel = new JPanel(new BorderLayout());
302         topPanel.add(namePanel, BorderLayout.LINE_START);
303         JLabel lblName = new JLabel("Name");
304         namePanel.add(lblName, BorderLayout.LINE_START);
305 
306         this.editName = new JFormattedTextField(System.getProperty("user.name"));
307         this.editName.setPreferredSize(new Dimension(100, 20));
308         namePanel.add(this.editName, BorderLayout.LINE_END);
309 
310         JPanel federationPanel = new JPanel(new BorderLayout());
311         topPanel.add(federationPanel, BorderLayout.CENTER);
312         JLabel lblFederation = new JLabel("Federation");
313         federationPanel.add(lblFederation, BorderLayout.LINE_START);
314 
315         this.editFederation = new JFormattedTextField(TConnection.DEFAULT_FEDERATION);
316         federationPanel.add(this.editFederation, BorderLayout.LINE_END);
317 
318         this.btnConnect = new JButton("Connect");
319         this.btnConnect.addActionListener(new ActionListener()
320         {
321             @Override
322             public void actionPerformed(ActionEvent e)
323             {
324                 if (IMBChat.this.btnConnect.getText().compareTo("Connect") == 0)
325                     Connect();
326                 else
327                     Disconnect();
328             }
329         });
330         
331         topPanel.add(this.btnConnect, BorderLayout.LINE_END);
332         
333         this.messages = new JTextArea("hier komen de messages");
334         mainPanel.add(this.messages, BorderLayout.CENTER);
335         
336         JPanel bottomPanel = new JPanel(new BorderLayout());
337         mainPanel.add(bottomPanel, BorderLayout.SOUTH);
338         this.editMessage = new JTextField("");
339         this.editMessage.addKeyListener(new KeyListener()
340         {
341             @Override
342             public void keyTyped(KeyEvent e)
343             {
344                 if (e.getKeyChar() == 13)
345                 {
346                     Send();
347                 }
348             }
349 
350             @Override
351             public void keyPressed(KeyEvent e)
352             {
353                 // ignore
354             }
355 
356             @Override
357             public void keyReleased(KeyEvent e)
358             {
359                 // ignore
360             }
361 
362         });
363         bottomPanel.add(this.editMessage, BorderLayout.CENTER);
364 
365         JButton btnSend = new JButton("Send");
366         btnSend.addActionListener(new ActionListener()
367         {
368             @Override
369             public void actionPerformed(ActionEvent e)
370             {
371                 Send();
372             }
373         });
374         bottomPanel.add(btnSend, BorderLayout.LINE_END);
375         this.pack();
376         this.setVisible(true);
377     }
378 
379 }