Changeset 33602 in osm for applications/editors
- Timestamp:
- 2017-09-14T23:12:25+02:00 (7 years ago)
- Location:
- applications/editors/josm/plugins/geochat
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
applications/editors/josm/plugins/geochat/build.xml
r33545 r33602 5 5 <property name="commit.message" value="[josm_geochat] copypaste from keyboard, font size advanced parameters"/> 6 6 <!-- enter the *lowest* JOSM version this plugin is currently compatible with --> 7 <property name="plugin.main.version" value="12 643"/>7 <property name="plugin.main.version" value="12743"/> 8 8 9 9 <property name="plugin.author" value="Ilya Zverev"/> -
applications/editors/josm/plugins/geochat/src/geochat/ChatPaneManager.java
r33545 r33602 32 32 */ 33 33 class ChatPaneManager { 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 34 private static final String PUBLIC_PANE = "Public Pane"; 35 36 private GeoChatPanel panel; 37 private JTabbedPane tabs; 38 private Map<String, ChatPane> chatPanes; 39 private boolean collapsed; 40 41 ChatPaneManager(GeoChatPanel panel, JTabbedPane tabs) { 42 this.panel = panel; 43 this.tabs = tabs; 44 this.collapsed = panel.isDialogInCollapsedView(); 45 chatPanes = new HashMap<>(); 46 createChatPane(null); 47 tabs.addChangeListener(new ChangeListener() { 48 @Override 49 public void stateChanged(ChangeEvent e) { 50 updateActiveTabStatus(); 51 } 52 }); 53 } 54 55 public void setCollapsed(boolean collapsed) { 56 this.collapsed = collapsed; 57 updateActiveTabStatus(); 58 } 59 60 public boolean hasUser(String user) { 61 return chatPanes.containsKey(user == null ? PUBLIC_PANE : user); 62 } 63 64 public Component getPublicChatComponent() { 65 return chatPanes.get(PUBLIC_PANE).component; 66 } 67 68 public int getNotifyLevel() { 69 int alarm = 0; 70 for (ChatPane entry : chatPanes.values()) { 71 if (entry.notify > alarm) 72 alarm = entry.notify; 73 } 74 return alarm; 75 } 76 77 public void updateActiveTabStatus() { 78 if (tabs.getSelectedIndex() >= 0) 79 ((ChatTabTitleComponent) tabs.getTabComponentAt(tabs.getSelectedIndex())).updateAlarm(); 80 } 81 82 public void notify(String user, int alarmLevel) { 83 if (alarmLevel <= 0 || !hasUser(user)) 84 return; 85 ChatPane entry = chatPanes.get(user == null ? PUBLIC_PANE : user); 86 entry.notify = alarmLevel; 87 int idx = tabs.indexOfComponent(entry.component); 88 if (idx >= 0) 89 ((ChatTabTitleComponent) tabs.getTabComponentAt(idx)).updateAlarm(); 90 } 91 92 public static int MESSAGE_TYPE_DEFAULT = 0; 93 public static int MESSAGE_TYPE_INFORMATION = 1; 94 public static int MESSAGE_TYPE_ATTENTION = 2; 95 private static Color COLOR_ATTENTION = new Color(0, 0, 192); 96 97 private void addLineToChatPane(String userName, String line, final int messageType) { 98 if (line.length() == 0) 99 return; 100 if (!chatPanes.containsKey(userName)) 101 createChatPane(userName); 102 final String nline = line.startsWith("\n") ? line : "\n" + line; 103 final JTextPane thepane = chatPanes.get(userName).pane; 104 GuiHelper.runInEDT(new Runnable() { 105 @Override 106 public void run() { 107 Document doc = thepane.getDocument(); 108 try { 109 SimpleAttributeSet attrs = null; 110 if (messageType != MESSAGE_TYPE_DEFAULT) { 111 attrs = new SimpleAttributeSet(); 112 if (messageType == MESSAGE_TYPE_INFORMATION) 113 StyleConstants.setItalic(attrs, true); 114 else if (messageType == MESSAGE_TYPE_ATTENTION) 115 StyleConstants.setForeground(attrs, COLOR_ATTENTION); 116 } 117 doc.insertString(doc.getLength(), nline, attrs); 118 } catch (BadLocationException ex) { 119 Logging.warn(ex); 120 } 121 thepane.setCaretPosition(doc.getLength()); 122 } 123 }); 124 } 125 126 public void addLineToChatPane(String userName, String line) { 127 addLineToChatPane(userName, line, MESSAGE_TYPE_DEFAULT); 128 } 129 130 public void addLineToPublic(String line) { 131 addLineToChatPane(PUBLIC_PANE, line); 132 } 133 134 public void addLineToPublic(String line, int messageType) { 135 addLineToChatPane(PUBLIC_PANE, line, messageType); 136 } 137 138 public void clearPublicChatPane() { 139 chatPanes.get(PUBLIC_PANE).pane.setText(""); 140 } 141 142 public void clearChatPane(String userName) { 143 if (userName == null || userName.equals(PUBLIC_PANE)) 144 clearPublicChatPane(); 145 else 146 chatPanes.get(userName).pane.setText(""); 147 } 148 149 public void clearActiveChatPane() { 150 clearChatPane(getActiveChatPane()); 151 } 152 153 public ChatPane createChatPane(String userName) { 154 JTextPane chatPane = new JTextPane(); 155 chatPane.setEditable(false); 156 Font font = chatPane.getFont(); 157 float size = Main.pref.getInteger("geochat.fontsize", -1); 158 if (size < 6) 159 size += font.getSize2D(); 160 chatPane.setFont(font.deriveFont(size)); 161 // DefaultCaret caret = (DefaultCaret)chatPane.getCaret(); // does not work 162 // caret.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE); 163 JScrollPane scrollPane = new JScrollPane(chatPane, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); 164 chatPane.addMouseListener(new GeoChatPopupAdapter(panel)); 165 166 ChatPane entry = new ChatPane(); 167 entry.pane = chatPane; 168 entry.component = scrollPane; 169 entry.notify = 0; 170 entry.userName = userName; 171 entry.isPublic = userName == null; 172 chatPanes.put(userName == null ? PUBLIC_PANE : userName, entry); 173 174 tabs.addTab(null, scrollPane); 175 tabs.setTabComponentAt(tabs.getTabCount() - 1, new ChatTabTitleComponent(entry)); 176 tabs.setSelectedComponent(scrollPane); 177 return entry; 178 } 179 180 /** 181 * Returns key in chatPanes hash map for the currently active 182 * chat pane, or null in case of an error. 183 */ 184 public String getActiveChatPane() { 185 Component c = tabs.getSelectedComponent(); 186 if (c == null) 187 return null; 188 for (String user : chatPanes.keySet()) { 189 if (c.equals(chatPanes.get(user).component)) 190 return user; 191 } 192 return null; 193 } 194 195 public String getRecipient() { 196 String user = getActiveChatPane(); 197 return user == null || user.equals(PUBLIC_PANE) ? null : user; 198 } 199 200 public 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 public void closeSelectedPrivatePane() { 208 String pane = getRecipient(); 209 if (pane != null) 210 closeChatPane(pane); 211 } 212 213 public void closePrivateChatPanes() { 214 List<String> entries = new ArrayList<>(chatPanes.keySet()); 215 for (String user : entries) { 216 if (!user.equals(PUBLIC_PANE)) 217 closeChatPane(user); 218 } 219 } 220 221 public boolean hasSelectedText() { 222 String user = getActiveChatPane(); 223 if (user != null) { 224 JTextPane pane = chatPanes.get(user).pane; 225 return pane.getSelectedText() != null; 226 } 227 return false; 228 } 229 230 public void copySelectedText() { 231 String user = getActiveChatPane(); 232 if (user != null) 233 chatPanes.get(user).pane.copy(); 234 } 235 236 private class ChatTabTitleComponent extends JLabel { 237 private ChatPane entry; 238 239 ChatTabTitleComponent(ChatPane entry) { 240 super(entry.isPublic ? tr("Public") : entry.userName); 241 this.entry = entry; 242 } 243 244 private Font normalFont; 245 private Font boldFont; 246 247 public void updateAlarm() { 248 if (normalFont == null) { 249 // prepare cached fonts 250 normalFont = getFont().deriveFont(Font.PLAIN); 251 boldFont = getFont().deriveFont(Font.BOLD); 252 } 253 if (entry.notify > 0 && !collapsed && tabs.getSelectedIndex() == tabs.indexOfComponent(entry.component)) 254 entry.notify = 0; 255 setFont(entry.notify > 0 ? boldFont : normalFont); 256 panel.updateTitleAlarm(); 257 } 258 } 259 260 static class ChatPane { 261 public String userName; 262 public boolean isPublic; 263 public JTextPane pane; 264 public JScrollPane component; 265 public int notify; 266 267 } 268 268 } -
applications/editors/josm/plugins/geochat/src/geochat/GeoChatPanel.java
r33545 r33602 36 36 import org.openstreetmap.josm.Main; 37 37 import org.openstreetmap.josm.data.Bounds; 38 import org.openstreetmap.josm.data.UserIdentityManager; 38 39 import org.openstreetmap.josm.data.coor.LatLon; 39 import org.openstreetmap.josm.gui.*; 40 import org.openstreetmap.josm.gui.MainApplication; 41 import org.openstreetmap.josm.gui.MapView; 42 import org.openstreetmap.josm.gui.Notification; 40 43 import org.openstreetmap.josm.gui.dialogs.ToggleDialog; 41 44 import org.openstreetmap.josm.gui.layer.MapViewPaintable; … … 50 53 */ 51 54 public class GeoChatPanel extends ToggleDialog implements ChatServerConnectionListener, MapViewPaintable { 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 userName = JosmUserIdentityManager.getInstance().getUserName();104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 55 private JTextField input; 56 private JTabbedPane tabs; 57 private JComponent noData; 58 private JPanel loginPanel; 59 private JPanel gcPanel; 60 private ChatServerConnection connection; 61 // those fields should be visible to popup menu actions 62 Map<String, LatLon> users; 63 ChatPaneManager chatPanes; 64 boolean userLayerActive; 65 66 public GeoChatPanel() { 67 super(tr("GeoChat"), "geochat", tr("Open GeoChat panel"), null, 200, true); 68 69 noData = new JLabel(tr("Zoom in to see messages"), SwingConstants.CENTER); 70 71 tabs = new JTabbedPane(); 72 tabs.addMouseListener(new GeoChatPopupAdapter(this)); 73 chatPanes = new ChatPaneManager(this, tabs); 74 75 input = new JPanelTextField() { 76 @Override 77 protected void processEnter(String text) { 78 connection.postMessage(text, chatPanes.getRecipient()); 79 } 80 81 @Override 82 protected String autoComplete(String word, boolean atStart) { 83 return autoCompleteUser(word, atStart); 84 } 85 }; 86 87 String defaultUserName = constructUserName(); 88 loginPanel = createLoginPanel(defaultUserName); 89 90 gcPanel = new JPanel(new BorderLayout()); 91 gcPanel.add(loginPanel, BorderLayout.CENTER); 92 createLayout(gcPanel, false, null); 93 94 users = new TreeMap<>(); 95 // Start threads 96 connection = ChatServerConnection.getInstance(); 97 connection.addListener(this); 98 boolean autoLogin = Main.pref.get("geochat.username", null) == null ? false : Main.pref.getBoolean("geochat.autologin", true); 99 connection.autoLoginWithDelay(autoLogin ? defaultUserName : null); 100 updateTitleAlarm(); 101 } 102 103 private String constructUserName() { 104 String userName = Main.pref.get("geochat.username", null); // so the default is null 105 if (userName == null) 106 userName = UserIdentityManager.getInstance().getUserName(); 107 if (userName == null) 108 userName = ""; 109 if (userName.contains("@")) 110 userName = userName.substring(0, userName.indexOf('@')); 111 userName = userName.replace(' ', '_'); 112 return userName; 113 } 114 115 private JPanel createLoginPanel(String defaultUserName) { 116 final JTextField nameField = new JPanelTextField() { 117 @Override 118 protected void processEnter(String text) { 119 connection.login(text); 120 } 121 }; 122 nameField.setText(defaultUserName); 123 124 JButton loginButton = new JButton(tr("Login")); 125 loginButton.addActionListener(new ActionListener() { 126 @Override 127 public void actionPerformed(ActionEvent e) { 128 connection.login(nameField.getText()); 129 } 130 }); 131 nameField.setPreferredSize(new Dimension(nameField.getPreferredSize().width, loginButton.getPreferredSize().height)); 132 133 final JCheckBox autoLoginBox = new JCheckBox(tr("Enable autologin"), Main.pref.getBoolean("geochat.autologin", true)); 134 autoLoginBox.addActionListener(new ActionListener() { 135 @Override 136 public void actionPerformed(ActionEvent e) { 137 Main.pref.put("geochat.autologin", autoLoginBox.isSelected()); 138 } 139 }); 140 141 JPanel panel = new JPanel(new GridBagLayout()); 142 panel.add(nameField, GBC.std().fill(GridBagConstraints.HORIZONTAL).insets(15, 0, 5, 0)); 143 panel.add(loginButton, GBC.eol().fill(GridBagConstraints.NONE).insets(0, 0, 15, 0)); 144 panel.add(autoLoginBox, GBC.std().insets(15, 0, 15, 0)); 145 return panel; 146 } 147 148 protected void logout() { 149 connection.logout(); 150 } 151 152 @Override 153 public void destroy() { 154 try { 155 if (Main.pref.getBoolean("geochat.logout.on.close", true)) { 156 connection.removeListener(this); 157 connection.bruteLogout(); 158 } 159 } catch (IOException e) { 160 Logging.warn("Failed to logout from geochat server: " + e.getMessage()); 161 } 162 super.destroy(); 163 } 164 165 private String autoCompleteUser(String word, boolean atStart) { 166 String result = null; 167 boolean singleUser = true; 168 for (String user : users.keySet()) { 169 if (user.startsWith(word)) { 170 if (result == null) 171 result = user; 172 else { 173 singleUser = false; 174 int i = word.length(); 175 while (i < result.length() && i < user.length() && result.charAt(i) == user.charAt(i)) { 176 i++; 177 } 178 if (i < result.length()) 179 result = result.substring(0, i); 180 } 181 } 182 } 183 return result == null ? null : !singleUser ? result : atStart ? result + ": " : result + " "; 184 } 185 186 /** 187 * This is implementation of a "temporary layer". It paints circles 188 * for all users nearby. 189 */ 190 @Override 191 public void paint(Graphics2D g, MapView mv, Bounds bbox) { 192 Graphics2D g2d = (Graphics2D) g.create(); 193 g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); 194 Composite ac04 = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.4f); 195 Composite ac10 = g2d.getComposite(); 196 197 Font font = g2d.getFont().deriveFont(Font.BOLD, g2d.getFont().getSize2D() + 2.0f); 198 g2d.setFont(font); 199 FontMetrics fm = g2d.getFontMetrics(); 200 201 for (String user : users.keySet()) { 202 int stringWidth = fm.stringWidth(user); 203 int radius = stringWidth / 2 + 10; 204 Point p = mv.getPoint(users.get(user)); 205 206 g2d.setComposite(ac04); 207 g2d.setColor(Color.white); 208 g2d.fillOval(p.x - radius, p.y - radius, radius * 2 + 1, radius * 2 + 1); 209 210 g2d.setComposite(ac10); 211 g2d.setColor(Color.black); 212 g2d.drawString(user, p.x - stringWidth / 2, p.y + fm.getDescent()); 213 } 214 } 215 216 /* ================== Notifications in the title ======================= */ 217 218 /** 219 * Display number of users and notifications in the panel title. 220 */ 221 protected void updateTitleAlarm() { 222 int alarmLevel = connection.isLoggedIn() ? chatPanes.getNotifyLevel() : 0; 223 if (!isDialogInCollapsedView() && alarmLevel > 1) 224 alarmLevel = 1; 225 226 String comment; 227 if (connection.isLoggedIn()) { 228 comment = trn("{0} user", "{0} users", users.size() + 1, users.size() + 1); 229 } else { 230 comment = tr("not logged in"); 231 } 232 233 String title = tr("GeoChat"); 234 if (comment != null) 235 title = title + " (" + comment + ")"; 236 final String alarm = (alarmLevel <= 0 ? "" : alarmLevel == 1 ? "* " : "!!! ") + title; 237 GuiHelper.runInEDT(new Runnable() { 238 @Override 239 public void run() { 240 setTitle(alarm); 241 } 242 }); 243 } 244 245 /** 246 * Track panel collapse events. 247 */ 248 @Override 249 protected void setIsCollapsed(boolean val) { 250 super.setIsCollapsed(val); 251 chatPanes.setCollapsed(val); 252 updateTitleAlarm(); 253 } 254 255 /* ============ ChatServerConnectionListener methods ============= */ 256 257 @Override 258 public void loggedIn(String userName) { 259 Main.pref.put("geochat.username", userName); 260 if (gcPanel.getComponentCount() == 1) { 261 GuiHelper.runInEDTAndWait(new Runnable() { 262 @Override 263 public void run() { 264 gcPanel.remove(0); 265 gcPanel.add(tabs, BorderLayout.CENTER); 266 gcPanel.add(input, BorderLayout.SOUTH); 267 } 268 }); 269 } 270 updateTitleAlarm(); 271 } 272 273 @Override 274 public void notLoggedIn(final String reason) { 275 if (reason != null) { 276 GuiHelper.runInEDT(new Runnable() { 277 @Override 278 public void run() { 279 new Notification(tr("Failed to log in to GeoChat:") + "\n" + reason).show(); 280 } 281 }); 282 } else { 283 // regular logout 284 if (gcPanel.getComponentCount() > 1) { 285 gcPanel.removeAll(); 286 gcPanel.add(loginPanel, BorderLayout.CENTER); 287 } 288 } 289 updateTitleAlarm(); 290 } 291 292 @Override 293 public void messageSendFailed(final String reason) { 294 GuiHelper.runInEDT(new Runnable() { 295 @Override 296 public void run() { 297 new Notification(tr("Failed to send message:") + "\n" + reason).show(); 298 } 299 }); 300 } 301 302 @Override 303 public void statusChanged(boolean active) { 304 // only the public tab, because private chats don't rely on coordinates 305 tabs.setComponentAt(0, active ? chatPanes.getPublicChatComponent() : noData); 306 repaint(); 307 } 308 309 @Override 310 public void updateUsers(Map<String, LatLon> newUsers) { 311 for (String uname : this.users.keySet()) { 312 if (!newUsers.containsKey(uname)) 313 chatPanes.addLineToPublic(tr("User {0} has left", uname), ChatPaneManager.MESSAGE_TYPE_INFORMATION); 314 } 315 for (String uname : newUsers.keySet()) { 316 if (!this.users.containsKey(uname)) 317 chatPanes.addLineToPublic(tr("User {0} is mapping nearby", uname), ChatPaneManager.MESSAGE_TYPE_INFORMATION); 318 } 319 this.users = newUsers; 320 updateTitleAlarm(); 321 if (userLayerActive && MainApplication.isDisplayingMapView()) 322 MainApplication.getMap().mapView.repaint(); 323 } 324 325 private final SimpleDateFormat TIME_FORMAT = new SimpleDateFormat("HH:mm"); 326 327 private void formatMessage(StringBuilder sb, ChatMessage msg) { 328 sb.append("\n"); 329 sb.append('[').append(TIME_FORMAT.format(msg.getTime())).append("] "); 330 sb.append(msg.getAuthor()).append(": ").append(msg.getMessage()); 331 } 332 333 @Override 334 public void receivedMessages(boolean replace, List<ChatMessage> messages) { 335 if (replace) 336 chatPanes.clearPublicChatPane(); 337 if (!messages.isEmpty()) { 338 int alarm = 0; 339 StringBuilder sb = new StringBuilder(); 340 for (ChatMessage msg : messages) { 341 boolean important = msg.isIncoming() && containsName(msg.getMessage()); 342 if (msg.isIncoming() && alarm < 2) { 343 alarm = important ? 2 : 1; 344 } 345 if (important) { 346 // add buffer, then add current line with italic, then clear buffer 347 chatPanes.addLineToPublic(sb.toString()); 348 sb.setLength(0); 349 formatMessage(sb, msg); 350 chatPanes.addLineToPublic(sb.toString(), ChatPaneManager.MESSAGE_TYPE_ATTENTION); 351 sb.setLength(0); 352 } else 353 formatMessage(sb, msg); 354 } 355 chatPanes.addLineToPublic(sb.toString()); 356 if (alarm > 0) 357 chatPanes.notify(null, alarm); 358 } 359 if (replace) 360 showNearbyUsers(); 361 } 362 363 private void showNearbyUsers() { 364 if (!users.isEmpty()) { 365 StringBuilder sb = new StringBuilder(tr("Users mapping nearby:")); 366 boolean first = true; 367 for (String user : users.keySet()) { 368 sb.append(first ? " " : ", "); 369 sb.append(user); 370 } 371 chatPanes.addLineToPublic(sb.toString(), ChatPaneManager.MESSAGE_TYPE_INFORMATION); 372 } 373 } 374 375 private boolean containsName(String message) { 376 String userName = connection.getUserName(); 377 int length = userName.length(); 378 int i = message.indexOf(userName); 379 while (i >= 0) { 380 if ((i == 0 || !Character.isJavaIdentifierPart(message.charAt(i - 1))) 381 && (i + length >= message.length() || !Character.isJavaIdentifierPart(message.charAt(i + length)))) 382 return true; 383 i = message.indexOf(userName, i + 1); 384 } 385 return false; 386 } 387 388 @Override 389 public void receivedPrivateMessages(boolean replace, List<ChatMessage> messages) { 390 if (replace) 391 chatPanes.closePrivateChatPanes(); 392 for (ChatMessage msg : messages) { 393 StringBuilder sb = new StringBuilder(); 394 formatMessage(sb, msg); 395 chatPanes.addLineToChatPane(msg.isIncoming() ? msg.getAuthor() : msg.getRecipient(), sb.toString()); 396 if (msg.isIncoming()) 397 chatPanes.notify(msg.getAuthor(), 2); 398 } 399 } 397 400 }
Note:
See TracChangeset
for help on using the changeset viewer.