Changeset 29568 in osm for applications/editors/josm
- Timestamp:
- 2013-05-09T11:03:28+02:00 (12 years ago)
- Location:
- applications/editors/josm/plugins/geochat/src/geochat
- Files:
-
- 3 added
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
applications/editors/josm/plugins/geochat/src/geochat/ChatMessage.java
r29558 r29568 17 17 private long id; 18 18 private boolean priv; 19 private boolean incoming; 19 20 20 public ChatMessage( long id, LatLon pos, String author, String message, Date time ) { 21 public ChatMessage( long id, LatLon pos, String author, boolean incoming, String message, Date time ) { 21 22 this.id = id; 22 23 this.author = author; … … 24 25 this.pos = pos; 25 26 this.time = time; 27 this.incoming = incoming; 26 28 this.priv = false; 27 29 this.recipient = null; … … 63 65 } 64 66 67 public boolean isIncoming() { 68 return incoming; 69 } 70 65 71 public Date getTime() { 66 72 return time; -
applications/editors/josm/plugins/geochat/src/geochat/ChatServerConnection.java
r29558 r29568 337 337 String author = msg.getString("author"); 338 338 String message = msg.getString("message"); 339 ChatMessage cm = new ChatMessage(id, new LatLon(lat, lon), author, message, new Date(timeStamp * 1000)); 339 boolean incoming = msg.getBoolean("incoming"); 340 ChatMessage cm = new ChatMessage(id, new LatLon(lat, lon), author, 341 incoming, message, new Date(timeStamp * 1000)); 340 342 cm.setPrivate(priv); 341 if( msg.has("recipient") && ! msg.getBoolean("incoming"))343 if( msg.has("recipient") && !incoming ) 342 344 cm.setRecipient(msg.getString("recipient")); 343 345 result.add(cm); -
applications/editors/josm/plugins/geochat/src/geochat/GeoChatPanel.java
r29563 r29568 8 8 import java.util.List; 9 9 import javax.swing.*; 10 import javax.swing.text.BadLocationException;11 import javax.swing.text.DefaultCaret;12 import javax.swing.text.Document;13 10 import org.openstreetmap.josm.Main; 14 11 import org.openstreetmap.josm.data.Bounds; … … 21 18 import static org.openstreetmap.josm.tools.I18n.tr; 22 19 import static org.openstreetmap.josm.tools.I18n.trn; 23 import org.openstreetmap.josm.tools.ImageProvider;24 20 25 21 /** 22 * Chat Panel. Contains of one public chat pane and multiple private ones. 26 23 * 27 24 * @author zverik 28 25 */ 29 26 public class GeoChatPanel extends ToggleDialog implements ChatServerConnectionListener, MapViewPaintable { 30 private static final String PUBLIC_PANE = "Public Pane";31 32 27 private JTextField input; 33 28 private JTabbedPane tabs; … … 36 31 private JPanel gcPanel; 37 32 private ChatServerConnection connection; 38 private Map<String, LatLon> users; 39 private Map<String, ChatLogEntry> chatPanes; 33 // those fields should be visible to popup menu actions 34 protected Map<String, LatLon> users; 35 protected ChatPaneManager chatPanes; 36 protected boolean userLayerActive; 40 37 41 38 public GeoChatPanel() { … … 44 41 noData = new JLabel(tr("Zoom in to see messages"), SwingConstants.CENTER); 45 42 46 chatPanes = new HashMap<String, ChatLogEntry>();47 43 tabs = new JTabbedPane(); 48 createChatPane(null); 49 50 tabs.addMouseListener(new PopupAdapter()); 44 tabs.addMouseListener(new GeoChatPopupAdapter(this)); 45 chatPanes = new ChatPaneManager(this, tabs); 51 46 52 47 input = new JPanelTextField() { 53 48 @Override 54 49 protected void processEnter( String text ) { 55 connection.postMessage(text, getRecipient()); 50 connection.postMessage(text, chatPanes.getRecipient()); 56 51 } 57 52 58 53 @Override 59 54 protected String autoComplete( String word ) { 60 return word;55 return autoCompleteUser(word); 61 56 } 62 57 }; 63 58 59 loginPanel = createLoginPanel(); 60 61 gcPanel = new JPanel(new BorderLayout()); 62 gcPanel.add(loginPanel, BorderLayout.CENTER); 63 createLayout(gcPanel, false, null); 64 65 users = new TreeMap<String, LatLon>(); 66 // Start threads 67 connection = ChatServerConnection.getInstance(); 68 connection.addListener(this); 69 connection.checkLogin(); 70 } 71 72 private JPanel createLoginPanel() { 64 73 final JTextField nameField = new JPanelTextField() { 65 74 @Override … … 73 82 if( userName.contains("@") ) 74 83 userName = userName.substring(0, userName.indexOf('@')); 84 userName = userName.replace(' ', '_'); 75 85 nameField.setText(userName); 76 86 … … 83 93 nameField.setPreferredSize(new Dimension(nameField.getPreferredSize().width, loginButton.getPreferredSize().height)); 84 94 85 loginPanel = new JPanel(new GridBagLayout()); 86 loginPanel.add(nameField, GBC.std().fill(GridBagConstraints.HORIZONTAL).insets(15, 0, 5, 0)); 87 loginPanel.add(loginButton, GBC.std().fill(GridBagConstraints.NONE).insets(0, 0, 15, 0)); 88 89 gcPanel = new JPanel(new BorderLayout()); 90 gcPanel.add(loginPanel, BorderLayout.CENTER); 91 createLayout(gcPanel, false, null); 92 93 users = new TreeMap<String, LatLon>(); 94 // Start threads 95 connection = ChatServerConnection.getInstance(); 96 connection.addListener(this); 97 connection.checkLogin(); 98 } 99 100 private void addLineToChatPane( String userName, String line ) { 101 if( !chatPanes.containsKey(userName) ) 102 createChatPane(userName); 103 if( !line.startsWith("\n") ) 104 line = "\n" + line; 105 Document doc = chatPanes.get(userName).pane.getDocument(); 106 try { 107 doc.insertString(doc.getLength(), line, null); 108 } catch( BadLocationException ex ) { 109 // whatever 110 } 111 } 112 113 private void addLineToPublic( String line ) { 114 addLineToChatPane(PUBLIC_PANE, line); 115 } 116 117 private void clearPublicChatPane() { 118 chatPanes.get(PUBLIC_PANE).pane.setText(""); 119 showNearbyUsers(); 120 } 121 122 private void clearChatPane( String userName) { 123 if( userName == null || userName.equals(PUBLIC_PANE) ) 124 clearPublicChatPane(); 125 else 126 chatPanes.get(userName).pane.setText(""); 127 } 128 129 private ChatLogEntry createChatPane( String userName ) { 130 JTextPane chatPane = new JTextPane(); 131 chatPane.setEditable(false); 132 Font font = chatPane.getFont(); 133 chatPane.setFont(font.deriveFont(font.getSize2D() - 2)); 134 DefaultCaret caret = (DefaultCaret)chatPane.getCaret(); 135 caret.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE); 136 JScrollPane scrollPane = new JScrollPane(chatPane, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); 137 chatPane.addMouseListener(new PopupAdapter()); 138 139 ChatLogEntry entry = new ChatLogEntry(); 140 entry.pane = chatPane; 141 entry.component = scrollPane; 142 entry.notify = false; 143 entry.userName = userName; 144 entry.isPublic = userName == null; 145 chatPanes.put(userName == null ? PUBLIC_PANE : userName, entry); 146 147 tabs.addTab(userName == null ? tr("Public") : userName, scrollPane); 148 tabs.setSelectedComponent(scrollPane); 149 return entry; 95 JPanel panel = new JPanel(new GridBagLayout()); 96 panel.add(nameField, GBC.std().fill(GridBagConstraints.HORIZONTAL).insets(15, 0, 5, 0)); 97 panel.add(loginButton, GBC.std().fill(GridBagConstraints.NONE).insets(0, 0, 15, 0)); 98 return panel; 99 } 100 101 protected void logout() { 102 connection.logout(); 103 } 104 105 private String autoCompleteUser( String word ) { 106 return word; // todo: write autocomplete 150 107 } 151 108 152 109 /** 153 * Returns key in chatPanes hash map for the currently active154 * chat pane, or null in case of an error.110 * This is implementation of a "temporary layer". It paints circles 111 * for all users nearby. 155 112 */ 156 private String getActiveChatPane() {157 Component c = tabs.getSelectedComponent();158 if( c == null )159 return null;160 for( String user : chatPanes.keySet() )161 if( c.equals(chatPanes.get(user).component) )162 return user;163 return null;164 }165 166 private String getRecipient() {167 String user = getActiveChatPane();168 return user == null || user.equals(PUBLIC_PANE) ? null : user;169 }170 171 private void closeChatPane( String user ) {172 if( user == null || user.equals(PUBLIC_PANE) || !chatPanes.containsKey(user) )173 return;174 tabs.remove(chatPanes.get(user).component);175 chatPanes.remove(user);176 }177 178 private void closePrivateChatPanes() {179 List<String> entries = new ArrayList<String>(chatPanes.keySet());180 for( String user : entries )181 if( !user.equals(PUBLIC_PANE) )182 closeChatPane(user);183 }184 185 private String cachedTitle = "";186 private int cachedAlarm = 0;187 188 @Override189 public void setTitle( String title ) {190 setTitle(title, -1);191 }192 193 private void setTitleAlarm( int alarmLevel ) {194 setTitle(null, alarmLevel);195 }196 197 private void setTitle( String title, int alarmLevel ) {198 if( title != null )199 cachedTitle = title;200 if( alarmLevel >= 0 )201 cachedAlarm = alarmLevel;202 String alarm = cachedAlarm <= 0 ? "" : cachedAlarm == 1 ? "* " : "[!] ";203 super.setTitle(alarm + cachedTitle);204 }205 206 113 public void paint( Graphics2D g, MapView mv, Bounds bbox ) { 207 114 Graphics2D g2d = (Graphics2D)g.create(); … … 227 134 g2d.drawString(user, p.x - Math.round(rect.getWidth() / 2), p.y); 228 135 } 136 } 137 138 /* ================== Notifications in the title ======================= */ 139 140 private String cachedTitle = null; 141 private int cachedAlarm = 0; 142 143 @Override 144 public void setTitle( String title ) { 145 setTitle(title, -1); 146 } 147 148 private void setTitle( String title, int alarmLevel ) { 149 boolean changed = false; 150 if( title != null && (cachedTitle == null || !cachedTitle.equals(title)) ) { 151 cachedTitle = title; 152 changed = true; 153 } 154 if( alarmLevel >= 0 && cachedAlarm != alarmLevel ) { 155 cachedAlarm = alarmLevel; 156 changed = true; 157 } 158 if( changed ) { 159 String alarm = cachedAlarm <= 0 ? "" : cachedAlarm == 1 ? "* " : "!!! "; 160 super.setTitle(alarm + cachedTitle); 161 // todo: title becomes cut off 162 } 163 } 164 165 protected void updateTitleAlarm() { 166 int notifyLevel = chatPanes.getNotifyLevel(); 167 setTitle(null, isDialogInCollapsedView() ? notifyLevel : Math.min(1, notifyLevel)); 168 } 169 170 @Override 171 protected void setIsCollapsed( boolean val ) { 172 super.setIsCollapsed(val); 173 chatPanes.setCollapsed(val); 174 updateTitleAlarm(); 229 175 } 230 176 … … 265 211 public void statusChanged( boolean active ) { 266 212 // only the public tab, because private chats don't rely on coordinates 267 tabs.setComponentAt(0, active ? chatPanes.get (PUBLIC_PANE).component : noData);213 tabs.setComponentAt(0, active ? chatPanes.getPublicChatComponent() : noData); 268 214 repaint(); 269 215 } … … 272 218 for( String uname : this.users.keySet() ) { 273 219 if( !newUsers.containsKey(uname) ) 274 addLineToPublic(tr("User {0} has left", uname)); 220 chatPanes.addLineToPublic(tr("User {0} has left", uname)); 275 221 } 276 222 for( String uname : newUsers.keySet() ) { 277 223 if( !this.users.containsKey(uname) ) 278 addLineToPublic(tr("User {0} is mapping nearby", uname)); 224 chatPanes.addLineToPublic(tr("User {0} is mapping nearby", uname)); 279 225 } 280 226 setTitle(trn("GeoChat ({0} user)", "GeoChat ({0} users)", newUsers.size(), newUsers.size())); 281 // todo: update users location282 227 this.users = newUsers; 283 } 284 285 private void showNearbyUsers() { 286 if( !users.isEmpty() ) { 287 StringBuilder sb = new StringBuilder(tr("Users mapping nearby:")); 288 boolean first = true; 289 for( String user : users.keySet() ) { 290 sb.append(first ? " " : ", "); 291 sb.append(user); 292 } 293 addLineToPublic(sb.toString()); 294 } 228 if( userLayerActive && Main.map.mapView != null ) 229 Main.map.mapView.repaint(); 295 230 } 296 231 … … 305 240 public void receivedMessages( boolean replace, List<ChatMessage> messages ) { 306 241 if( replace ) 307 clearPublicChatPane(); 242 chatPanes.clearPublicChatPane(); 308 243 if( !messages.isEmpty() ) { 244 int alarm = 0; 309 245 StringBuilder sb = new StringBuilder(); 310 for( ChatMessage msg : messages ) 246 for( ChatMessage msg : messages ) { 311 247 formatMessage(sb, msg); 312 addLineToPublic(sb.toString()); 248 if( msg.isIncoming() ) { 249 // todo: alarm=2 for private messages 250 alarm = 1; 251 } 252 } 253 chatPanes.addLineToPublic(sb.toString()); 254 if( alarm > 0 ) 255 chatPanes.notify(null, alarm > 1); 313 256 } 314 257 } … … 316 259 public void receivedPrivateMessages( boolean replace, List<ChatMessage> messages ) { 317 260 if( replace ) 318 closePrivateChatPanes(); 261 chatPanes.closePrivateChatPanes(); 319 262 for( ChatMessage msg : messages ) { 320 263 StringBuilder sb = new StringBuilder(); 321 264 formatMessage(sb, msg); 322 addLineToChatPane(msg.getRecipient() != null ? msg.getRecipient() : msg.getAuthor(), sb.toString()); 323 } 324 } 325 326 /* =================== Service classes ==================== */ 327 328 private class JPanelTextField extends JTextField { 329 @Override 330 protected void processKeyEvent( KeyEvent e ) { 331 if( e.getID() == KeyEvent.KEY_PRESSED ) { 332 int code = e.getKeyCode(); 333 if( code == KeyEvent.VK_ENTER ) { 334 String text = input.getText(); 335 if( text.length() > 0 ) { 336 processEnter(text); 337 input.setText(""); 338 } 339 } else if( code == KeyEvent.VK_TAB ) { 340 autoComplete(""); // todo 341 } else if( code == KeyEvent.VK_ESCAPE ) { 342 if( Main.map != null && Main.map.mapView != null ) 343 Main.map.mapView.requestFocus(); 344 } 345 // Do not pass other events to JOSM 346 if( code != KeyEvent.VK_LEFT && code != KeyEvent.VK_HOME && code != KeyEvent.VK_RIGHT 347 && code != KeyEvent.VK_END && code != KeyEvent.VK_BACK_SPACE && code != KeyEvent.VK_DELETE ) 348 e.consume(); 349 } 350 super.processKeyEvent(e); 351 } 352 353 protected void processEnter( String text ) { } 354 355 protected String autoComplete( String word ) { return word; } 356 } 357 358 private class ChatLogEntry { 359 public String userName; 360 public boolean isPublic; 361 public JTextPane pane; 362 public JScrollPane component; 363 public boolean notify; 364 } 365 366 /* ================= Actions for popup menu ==================== */ 367 368 369 private JPopupMenu createPopupMenu() { 370 JMenu userMenu = new JMenu(tr("Private chat")); 371 for( String user : users.keySet() ) { 372 if( !chatPanes.containsKey(user) ) 373 userMenu.add(new PrivateChatAction(user)); 374 } 375 376 JPopupMenu menu = new JPopupMenu(); 377 menu.add(new JCheckBoxMenuItem(new ToggleUserLayerAction())); 378 if( userMenu.getItemCount() > 0 ) 379 menu.add(userMenu); 380 if( getRecipient() != null ) 381 menu.add(new CloseTabAction()); 382 // menu.add(new ClearPaneAction()); 383 // menu.add(new LogoutAction()); 384 return menu; 385 } 386 387 private class PopupAdapter extends MouseAdapter { 388 @Override public void mousePressed( MouseEvent e ) { check(e); } 389 @Override public void mouseReleased( MouseEvent e ) { check(e); } 390 391 private void check( MouseEvent e ) { 392 if( e.isPopupTrigger() ) { 393 createPopupMenu().show(tabs, e.getX(), e.getY()); 394 } 395 } 396 } 397 398 private class PrivateChatAction extends AbstractAction { 399 private String userName; 400 401 public PrivateChatAction( String userName ) { 402 super(userName); 403 this.userName = userName; 404 } 405 406 public void actionPerformed( ActionEvent e ) { 407 if( !chatPanes.containsKey(userName) ) { 408 ChatLogEntry entry = createChatPane(userName); 409 } 410 } 411 } 412 413 private class CloseTabAction extends AbstractAction { 414 public CloseTabAction() { 415 super(tr("Close tab")); 416 // putValue(SMALL_ICON, ImageProvider.get("help")); 417 } 418 419 public void actionPerformed( ActionEvent e ) { 420 String pane = getActiveChatPane(); 421 if( pane != null && !pane.equals(PUBLIC_PANE) ) 422 closeChatPane(pane); 423 } 424 } 425 426 private class LogoutAction extends AbstractAction { 427 public LogoutAction() { 428 super(tr("Logout")); 429 // putValue(SMALL_ICON, ImageProvider.get("help")); 430 } 431 432 public void actionPerformed( ActionEvent e ) { 433 connection.logout(); 434 } 435 } 436 437 private class ClearPaneAction extends AbstractAction { 438 public ClearPaneAction() { 439 super(tr("Clear log")); 440 // putValue(SMALL_ICON, ImageProvider.get("help")); 441 } 442 443 public void actionPerformed( ActionEvent e ) { 444 clearChatPane(getActiveChatPane()); 445 } 446 } 447 448 private class ToggleUserLayerAction extends AbstractAction { 449 public ToggleUserLayerAction() { 450 super(tr("Show users on map")); 451 // putValue(SMALL_ICON, ImageProvider.get("help")); 452 } 453 454 public void actionPerformed( ActionEvent e ) { 455 if( Main.map == null || Main.map.mapView == null ) 456 return; 457 boolean wasAdded = Main.map.mapView.addTemporaryLayer(GeoChatPanel.this); 458 if( !wasAdded ) 459 Main.map.mapView.removeTemporaryLayer(GeoChatPanel.this); 460 Main.map.mapView.repaint(); 461 if( e.getSource() != null ) 462 System.out.println("toggle source: " + e.getSource().getClass().getName()); 463 if( e.getSource() instanceof JCheckBoxMenuItem ) 464 ((JCheckBoxMenuItem)e.getSource()).setSelected(wasAdded); 265 chatPanes.addLineToChatPane(msg.isIncoming() ? msg.getAuthor() : msg.getRecipient(), sb.toString()); 266 if( msg.isIncoming() ) 267 chatPanes.notify(msg.getAuthor(), true); 465 268 } 466 269 }
Note:
See TracChangeset
for help on using the changeset viewer.