Changeset 29558 in osm for applications/editors/josm/plugins/geochat
- Timestamp:
- 2013-05-05T11:36:55+02:00 (12 years ago)
- Location:
- applications/editors/josm/plugins/geochat
- Files:
-
- 2 added
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
applications/editors/josm/plugins/geochat/src/geochat/ChatMessage.java
r29540 r29558 13 13 private Date time; 14 14 private String author; 15 private String recipient; 15 16 private String message; 16 17 private long id; … … 24 25 this.time = time; 25 26 this.priv = false; 27 this.recipient = null; 28 } 29 30 public void setRecipient( String recipient ) { 31 this.recipient = recipient; 26 32 } 27 33 … … 32 38 public String getAuthor() { 33 39 return author; 40 } 41 42 /** 43 * Is only set when the message is not incoming, that is, author is the current user. 44 */ 45 public String getRecipient() { 46 return recipient; 34 47 } 35 48 -
applications/editors/josm/plugins/geochat/src/geochat/ChatServerConnection.java
r29541 r29558 4 4 import java.net.URLEncoder; 5 5 import java.util.*; 6 import javax.swing.SwingUtilities; 6 7 import org.json.JSONArray; 7 8 import org.json.JSONException; … … 113 114 } 114 115 116 private void logoutIntl() { 117 ChatServerConnection.this.userId = 0; 118 ChatServerConnection.this.userName = null; 119 Main.pref.put("geochat.lastuid", null); 120 for( ChatServerConnectionListener listener : listeners ) 121 listener.notLoggedIn(null); 122 } 123 115 124 private void fireLoginFailed( String reason ) { 116 125 for( ChatServerConnectionListener listener : listeners ) … … 128 137 public void processJson( JSONObject json ) { 129 138 if( json != null && json.has("message") ) { 130 ChatServerConnection.this.userId = 0; 131 ChatServerConnection.this.userName = null; 132 Main.pref.put("geochat.lastuid", null); 139 logoutIntl(); 133 140 } 134 141 } … … 279 286 lastUserId = userId; 280 287 lastPosition = pos; 281 288 282 289 String query = "get&lat=" + pos.latToString(CoordinateFormat.DECIMAL_DEGREES) 283 290 + "&lon=" + pos.lonToString(CoordinateFormat.DECIMAL_DEGREES) … … 285 292 JsonQueryUtil.queryAsync(query, new JsonQueryCallback() { 286 293 public void processJson( JSONObject json ) { 287 if( json == null ) 288 fireLoginFailed(tr("Could not get server response, check logs")); 289 else if( json.has("error") ) 290 fireLoginFailed(tr("Failed to login as {0}:", userName) + "\n" + json.getString("error")); 291 else { 294 if( json == null ) { 295 // do nothing? 296 // fireLoginFailed(tr("Could not get server response, check logs")); 297 // logoutIntl(); // todo: uncomment? 298 } else if( json.has("error") ) { 299 fireLoginFailed(tr("Failed to get messages as {0}:", userName) + "\n" + json.getString("error")); 300 logoutIntl(); 301 } else { 292 302 if( json.has("users") ) { 293 303 Map<String, LatLon> users = parseUsers(json.getJSONArray("users")); … … 329 339 ChatMessage cm = new ChatMessage(id, new LatLon(lat, lon), author, message, new Date(timeStamp * 1000)); 330 340 cm.setPrivate(priv); 341 if( msg.has("recipient") && !msg.getBoolean("incoming") ) 342 cm.setRecipient(msg.getString("recipient")); 331 343 result.add(cm); 332 344 } catch( JSONException e ) { -
applications/editors/josm/plugins/geochat/src/geochat/ChatServerConnectionListener.java
r29540 r29558 18 18 /** 19 19 * User tried to log in, but failed. 20 * @param reason Why. 20 * @param reason Why. <tt>null</tt> if it is intended logout. 21 21 */ 22 22 void notLoggedIn( String reason ); … … 50 50 * New private messages were received. See {@link #receivedMessages(boolean, java.util.List)}. 51 51 * Note that the array of messages can be reset, for example, when user has changed. 52 * Also, private messages go both way: check the recipient field. 52 53 * @param replace if set, remove all old messages. 53 54 * @param messages list of new private messages. -
applications/editors/josm/plugins/geochat/src/geochat/GeoChatPanel.java
r29557 r29558 1 1 package geochat; 2 2 3 import java.awt.BorderLayout; 4 import java.awt.Font; 5 import java.awt.event.ActionEvent; 6 import java.awt.event.ActionListener; 7 import java.awt.event.KeyEvent; 3 import java.awt.*; 4 import java.awt.event.*; 5 import java.awt.geom.Rectangle2D; 8 6 import java.text.SimpleDateFormat; 9 7 import java.util.*; 10 import java.util. logging.*;8 import java.util.List; 11 9 import javax.swing.*; 12 10 import javax.swing.text.BadLocationException; 11 import javax.swing.text.DefaultCaret; 13 12 import javax.swing.text.Document; 14 13 import org.openstreetmap.josm.Main; 14 import org.openstreetmap.josm.data.Bounds; 15 15 import org.openstreetmap.josm.data.coor.LatLon; 16 16 import org.openstreetmap.josm.gui.JosmUserIdentityManager; 17 import org.openstreetmap.josm.gui.MapView; 17 18 import org.openstreetmap.josm.gui.dialogs.ToggleDialog; 19 import org.openstreetmap.josm.gui.layer.MapViewPaintable; 20 import org.openstreetmap.josm.tools.GBC; 18 21 import static org.openstreetmap.josm.tools.I18n.tr; 19 22 import static org.openstreetmap.josm.tools.I18n.trn; 23 import org.openstreetmap.josm.tools.ImageProvider; 20 24 21 25 /** … … 23 27 * @author zverik 24 28 */ 25 public class GeoChatPanel extends ToggleDialog implements ChatServerConnectionListener { 26 27 private JTextPane chatPane; 29 public class GeoChatPanel extends ToggleDialog implements ChatServerConnectionListener, MapViewPaintable { 30 private static final String PUBLIC_PANE = "Public Pane"; 31 28 32 private JTextField input; 29 33 private JTabbedPane tabs; … … 33 37 private ChatServerConnection connection; 34 38 private Map<String, LatLon> users; 39 private Map<String, ChatLogEntry> chatPanes; 35 40 36 41 public GeoChatPanel() { 37 42 super(tr("GeoChat"), "geochat", tr("Open GeoChat panel"), null, 200, true); 38 43 39 chatPane = new JTextPane();40 chatPane.setEditable(false);41 Font font = chatPane.getFont();42 chatPane.setFont(font.deriveFont(font.getSize2D() - 2));43 44 44 noData = new JLabel(tr("Zoom in to see messages"), SwingConstants.CENTER); 45 45 46 chatPanes = new HashMap<String, ChatLogEntry>(); 46 47 tabs = new JTabbedPane(); 47 tabs.addTab(tr("Public"), new JScrollPane(chatPane, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER)); 48 createChatPane(null); 49 50 tabs.addMouseListener(new MouseAdapter() { 51 @Override public void mousePressed( MouseEvent e ) { check(e); } 52 @Override public void mouseReleased( MouseEvent e ) { check(e); } 53 54 private void check( MouseEvent e ) { 55 if( e.isPopupTrigger() ) { 56 createPopupMenu().show(tabs, e.getX(), e.getY()); 57 } 58 } 59 }); 48 60 49 61 input = new JPanelTextField() { 50 62 @Override 51 63 protected void processEnter( String text ) { 52 connection.postMessage(text); 64 connection.postMessage(text, getRecipient()); 53 65 } 54 66 … … 78 90 } 79 91 }); 80 81 loginPanel = new JPanel(new BorderLayout()); 82 loginPanel.add(nameField, BorderLayout.CENTER); 83 loginPanel.add(loginButton, BorderLayout.EAST); 84 loginPanel.add(Box.createVerticalGlue(), BorderLayout.NORTH); 85 loginPanel.add(Box.createVerticalGlue(), BorderLayout.SOUTH); 92 nameField.setPreferredSize(new Dimension(nameField.getPreferredSize().width, loginButton.getPreferredSize().height)); 93 94 // loginPanel = new JPanel(new BorderLayout()); 95 // loginPanel.add(nameField, BorderLayout.CENTER); 96 // loginPanel.add(loginButton, BorderLayout.EAST); 97 loginPanel = new JPanel(new GridBagLayout()); 98 loginPanel.add(nameField, GBC.std().fill(GridBagConstraints.HORIZONTAL).insets(15, 0, 5, 0)); 99 loginPanel.add(loginButton, GBC.std().fill(GridBagConstraints.NONE).insets(0, 0, 15, 0)); 86 100 87 101 gcPanel = new JPanel(new BorderLayout()); … … 89 103 createLayout(gcPanel, false, null); 90 104 91 users = new HashMap<String, LatLon>();105 users = new TreeMap<String, LatLon>(); 92 106 // Start threads 93 107 connection = ChatServerConnection.getInstance(); … … 95 109 connection.checkLogin(); 96 110 } 97 98 private void addLineToPublic( String line ) { 99 Document doc = chatPane.getDocument(); 111 112 private JPopupMenu createPopupMenu() { 113 JMenu userMenu = new JMenu(tr("Private chat")); 114 for( String user : users.keySet() ) { 115 if( !chatPanes.containsKey(user) ) 116 userMenu.add(new PrivateChatAction(user)); 117 } 118 119 JPopupMenu menu = new JPopupMenu(); 120 menu.add(new JCheckBoxMenuItem(new ToggleUserLayerAction())); 121 if( userMenu.getComponentCount() > 0 ) 122 menu.add(userMenu); 123 if( getRecipient() != null ) 124 menu.add(new CloseTabAction()); 125 menu.add(new ClearPaneAction()); 126 menu.add(new LogoutAction()); 127 return menu; 128 } 129 130 private void addLineToChatPane( String userName, String line ) { 131 if( !chatPanes.containsKey(userName) ) 132 createChatPane(userName); 133 if( !line.startsWith("\n") ) 134 line = "\n" + line; 135 Document doc = chatPanes.get(userName).pane.getDocument(); 100 136 try { 101 137 doc.insertString(doc.getLength(), line, null); … … 105 141 } 106 142 143 private void addLineToPublic( String line ) { 144 addLineToChatPane(PUBLIC_PANE, line); 145 } 146 147 private void clearPublicChatPane() { 148 chatPanes.get(PUBLIC_PANE).pane.setText(""); 149 showNearbyUsers(); 150 } 151 152 private void clearChatPane( String userName) { 153 if( userName == null || userName.equals(PUBLIC_PANE) ) 154 clearPublicChatPane(); 155 else 156 chatPanes.get(userName).pane.setText(""); 157 } 158 159 private ChatLogEntry createChatPane( String userName ) { 160 JTextPane chatPane = new JTextPane(); 161 chatPane.setEditable(false); 162 Font font = chatPane.getFont(); 163 chatPane.setFont(font.deriveFont(font.getSize2D() - 2)); 164 DefaultCaret caret = (DefaultCaret)chatPane.getCaret(); 165 caret.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE); 166 JScrollPane scrollPane = new JScrollPane(chatPane, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); 167 168 ChatLogEntry entry = new ChatLogEntry(); 169 entry.pane = chatPane; 170 entry.component = scrollPane; 171 entry.notify = false; 172 entry.userName = userName; 173 entry.isPublic = userName == null; 174 chatPanes.put(userName == null ? PUBLIC_PANE : userName, entry); 175 176 tabs.addTab(userName == null ? tr("Public") : userName, scrollPane); 177 tabs.setSelectedComponent(scrollPane); 178 return entry; 179 } 180 181 /** 182 * Returns key in chatPanes hash map for the currently active 183 * chat pane, or null in case of an error. 184 */ 185 private String getActiveChatPane() { 186 Component c = tabs.getSelectedComponent(); 187 if( c == null ) 188 return null; 189 for( String user : chatPanes.keySet() ) 190 if( c.equals(chatPanes.get(user).component) ) 191 return user; 192 return null; 193 } 194 195 private String getRecipient() { 196 String user = getActiveChatPane(); 197 return user == null || user.equals(PUBLIC_PANE) ? null : user; 198 } 199 200 private void closeChatPane( String user ) { 201 if( user == null || user.equals(PUBLIC_PANE) || !chatPanes.containsKey(user) ) 202 return; 203 tabs.remove(chatPanes.get(user).component); 204 chatPanes.remove(user); 205 } 206 207 private void closePrivateChatPanes() { 208 List<String> entries = new ArrayList<String>(chatPanes.keySet()); 209 for( String user : entries ) 210 if( !user.equals(PUBLIC_PANE) ) 211 closeChatPane(user); 212 } 213 107 214 private String cachedTitle = ""; 108 215 private int cachedAlarm = 0; 109 216 217 @Override 110 218 public void setTitle( String title ) { 111 219 setTitle(title, -1); … … 125 233 } 126 234 235 public void paint( Graphics2D g, MapView mv, Bounds bbox ) { 236 Graphics2D g2d = (Graphics2D)g.create(); 237 g2d.setColor(Color.yellow); 238 g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.3f)); 239 240 int zoom = ChatServerConnection.getCurrentZoom(); 241 int radius = Math.max(zoom, 1) * 10; 242 if( zoom < 14 ) 243 radius /= 2; 244 245 Font font = g2d.getFont().deriveFont(Math.min(zoom * 2, 8)); 246 g2d.setFont(font); 247 FontMetrics fm = g2d.getFontMetrics(); 248 249 for( String user : users.keySet() ) { 250 Point p = mv.getPoint(users.get(user)); 251 g2d.setColor(Color.yellow); 252 g2d.fillOval(p.x - radius, p.y - radius, radius * 2 + 1, radius * 2 + 1); 253 254 g2d.setColor(Color.black); 255 Rectangle2D rect = fm.getStringBounds(user, g2d); 256 g2d.drawString(user, p.x - Math.round(rect.getWidth() / 2), p.y); 257 } 258 } 259 127 260 public void loggedIn( String userName ) { 128 261 if( gcPanel.getComponentCount() == 1 ) { … … 133 266 } 134 267 135 public void notLoggedIn( String reason ) { 136 JOptionPane.showMessageDialog(Main.parent, reason); 137 } 138 139 public void messageSendFailed( String reason ) { 268 public void notLoggedIn( final String reason ) { 269 if( reason != null ) { 270 SwingUtilities.invokeLater(new Runnable() { 271 public void run() { 272 JOptionPane.showMessageDialog(Main.parent, reason); 273 } 274 }); 275 } else { 276 // regular logout 277 if( gcPanel.getComponentCount() > 1 ) { 278 gcPanel.removeAll(); 279 gcPanel.add(loginPanel, BorderLayout.CENTER); 280 } 281 } 282 } 283 284 public void messageSendFailed( final String reason ) { 285 SwingUtilities.invokeLater(new Runnable() { 286 public void run() { 287 JOptionPane.showMessageDialog(Main.parent, reason); 288 } 289 }); 140 290 } 141 291 142 292 public void statusChanged( boolean active ) { 143 tabs.setComponentAt(0, active ? chatPane : noData); 293 // only the public tab, because private chats don't rely on coordinates 294 tabs.setComponentAt(0, active ? chatPanes.get(PUBLIC_PANE).component : noData); 144 295 repaint(); 145 296 } 146 297 147 public void updateUsers( Map<String, LatLon> users ) { 148 for( String name : this.users.keySet() ) { 149 if( !users.containsKey(name) ) 150 addLineToPublic(tr("User {0} has left", name)); 151 } 152 for( String name : users.keySet() ) { 153 if( !this.users.containsKey(name) ) 154 addLineToPublic(tr("User {0} is mapping nearby", name)); 155 } 156 // todo: update header with user count 157 setTitle(trn("GeoChat ({0} user)", "GeoChat ({0} users)", users.size(), users.size())); 298 public void updateUsers( Map<String, LatLon> newUsers ) { 299 for( String uname : this.users.keySet() ) { 300 if( !newUsers.containsKey(uname) ) 301 addLineToPublic(tr("User {0} has left", uname)); 302 } 303 for( String uname : newUsers.keySet() ) { 304 if( !this.users.containsKey(uname) ) 305 addLineToPublic(tr("User {0} is mapping nearby", uname)); 306 } 307 setTitle(trn("GeoChat ({0} user)", "GeoChat ({0} users)", newUsers.size(), newUsers.size())); 158 308 // todo: update users location 159 this.users = users; 309 this.users = newUsers; 310 } 311 312 private void showNearbyUsers() { 313 if( !users.isEmpty() ) { 314 StringBuilder sb = new StringBuilder(tr("Users mapping nearby:")); 315 boolean first = true; 316 for( String user : users.keySet() ) { 317 sb.append(first ? " " : ", "); 318 sb.append(user); 319 } 320 addLineToPublic(sb.toString()); 321 } 160 322 } 161 323 162 324 private final SimpleDateFormat TIME_FORMAT = new SimpleDateFormat("HH:mm"); 325 326 private void formatMessage( StringBuilder sb, ChatMessage msg ) { 327 sb.append("\n"); 328 sb.append('[').append(TIME_FORMAT.format(msg.getTime())).append("] "); 329 sb.append(msg.getAuthor()).append(": ").append(msg.getMessage()); 330 } 331 163 332 public void receivedMessages( boolean replace, List<ChatMessage> messages ) { 164 if( replace ) { 165 chatPane.setText(""); 166 } 167 StringBuilder sb = new StringBuilder(); 333 if( replace ) 334 clearPublicChatPane(); 335 if( !messages.isEmpty() ) { 336 StringBuilder sb = new StringBuilder(); 337 for( ChatMessage msg : messages ) 338 formatMessage(sb, msg); 339 addLineToPublic(sb.toString()); 340 } 341 } 342 343 public void receivedPrivateMessages( boolean replace, List<ChatMessage> messages ) { 344 if( replace ) 345 closePrivateChatPanes(); 168 346 for( ChatMessage msg : messages ) { 169 sb.append('\n'); 170 sb.append('[').append(TIME_FORMAT.format(msg.getTime())).append("] "); 171 sb.append(msg.getAuthor()).append(": ").append(msg.getMessage()); 172 } 173 addLineToPublic(sb.toString()); 174 } 175 176 public void receivedPrivateMessages( boolean replace, List<ChatMessage> messages ) { 347 StringBuilder sb = new StringBuilder(); 348 formatMessage(sb, msg); 349 addLineToChatPane(msg.getRecipient() != null ? msg.getRecipient() : msg.getAuthor(), sb.toString()); 350 } 177 351 } 178 352 … … 206 380 protected String autoComplete( String word ) { return word; } 207 381 } 382 383 private class ChatLogEntry { 384 public String userName; 385 public boolean isPublic; 386 public JTextPane pane; 387 public JScrollPane component; 388 public boolean notify; 389 } 390 391 private class PrivateChatAction extends AbstractAction { 392 private String userName; 393 394 public PrivateChatAction( String userName ) { 395 super(userName); 396 this.userName = userName; 397 } 398 399 public void actionPerformed( ActionEvent e ) { 400 if( !chatPanes.containsKey(userName) ) { 401 ChatLogEntry entry = createChatPane(userName); 402 } 403 } 404 } 405 406 private class CloseTabAction extends AbstractAction { 407 public CloseTabAction() { 408 super(tr("Close tab")); 409 putValue(SMALL_ICON, ImageProvider.get("help")); 410 } 411 412 public void actionPerformed( ActionEvent e ) { 413 String pane = getActiveChatPane(); 414 if( pane != null && !pane.equals(PUBLIC_PANE) ) 415 closeChatPane(pane); 416 } 417 } 418 419 private class LogoutAction extends AbstractAction { 420 public LogoutAction() { 421 super(tr("Logout")); 422 putValue(SMALL_ICON, ImageProvider.get("help")); 423 } 424 425 public void actionPerformed( ActionEvent e ) { 426 connection.logout(); 427 } 428 } 429 430 private class ClearPaneAction extends AbstractAction { 431 public ClearPaneAction() { 432 super(tr("Clear log")); 433 putValue(SMALL_ICON, ImageProvider.get("help")); 434 } 435 436 public void actionPerformed( ActionEvent e ) { 437 clearChatPane(getActiveChatPane()); 438 } 439 } 440 441 private class ToggleUserLayerAction extends AbstractAction { 442 public ToggleUserLayerAction() { 443 super(tr("Show users on map")); 444 putValue(SMALL_ICON, ImageProvider.get("help")); 445 } 446 447 public void actionPerformed( ActionEvent e ) { 448 if( Main.map == null || Main.map.mapView == null ) 449 return; 450 boolean wasAdded = Main.map.mapView.addTemporaryLayer(GeoChatPanel.this); 451 if( !wasAdded ) 452 Main.map.mapView.removeTemporaryLayer(GeoChatPanel.this); 453 Main.map.mapView.repaint(); 454 if( e.getSource() != null ) 455 System.out.println("toggle source: " + e.getSource().getClass().getName()); 456 if( e.getSource() instanceof JCheckBoxMenuItem ) 457 ((JCheckBoxMenuItem)e.getSource()).setSelected(wasAdded); 458 } 459 } 208 460 } -
applications/editors/josm/plugins/geochat/src/geochat/JsonQueryUtil.java
r29541 r29558 29 29 String serverURL = Main.pref.get("geochat.server", "http://zverik.dev.openstreetmap.org/osmochat.php?action="); 30 30 URL url = new URL(serverURL + query); 31 //System.out.println("GeoChat URL = " + url.toString());31 System.out.println("GeoChat URL = " + url.toString()); 32 32 HttpURLConnection connection = (HttpURLConnection)url.openConnection(); 33 33 connection.connect();
Note:
See TracChangeset
for help on using the changeset viewer.