Ignore:
Timestamp:
2013-05-05T11:36:55+02:00 (11 years ago)
Author:
zverik
Message:

private chat should work

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  
    1313    private Date time;
    1414    private String author;
     15    private String recipient;
    1516    private String message;
    1617    private long id;
     
    2425        this.time = time;
    2526        this.priv = false;
     27        this.recipient = null;
     28    }
     29
     30    public void setRecipient( String recipient ) {
     31        this.recipient = recipient;
    2632    }
    2733
     
    3238    public String getAuthor() {
    3339        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;
    3447    }
    3548
  • applications/editors/josm/plugins/geochat/src/geochat/ChatServerConnection.java

    r29541 r29558  
    44import java.net.URLEncoder;
    55import java.util.*;
     6import javax.swing.SwingUtilities;
    67import org.json.JSONArray;
    78import org.json.JSONException;
     
    113114    }
    114115
     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
    115124    private void fireLoginFailed( String reason ) {
    116125        for( ChatServerConnectionListener listener : listeners )
     
    128137            public void processJson( JSONObject json ) {
    129138                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();
    133140                }
    134141            }
     
    279286            lastUserId = userId;
    280287            lastPosition = pos;
    281 
     288           
    282289            String query = "get&lat=" + pos.latToString(CoordinateFormat.DECIMAL_DEGREES)
    283290                    + "&lon=" + pos.lonToString(CoordinateFormat.DECIMAL_DEGREES)
     
    285292            JsonQueryUtil.queryAsync(query, new JsonQueryCallback() {
    286293                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 {
    292302                        if( json.has("users") ) {
    293303                            Map<String, LatLon> users = parseUsers(json.getJSONArray("users"));
     
    329339                    ChatMessage cm = new ChatMessage(id, new LatLon(lat, lon), author, message, new Date(timeStamp * 1000));
    330340                    cm.setPrivate(priv);
     341                    if( msg.has("recipient") && !msg.getBoolean("incoming") )
     342                        cm.setRecipient(msg.getString("recipient"));
    331343                    result.add(cm);
    332344                } catch( JSONException e ) {
  • applications/editors/josm/plugins/geochat/src/geochat/ChatServerConnectionListener.java

    r29540 r29558  
    1818    /**
    1919     * User tried to log in, but failed.
    20      * @param reason Why.
     20     * @param reason Why. <tt>null</tt> if it is intended logout.
    2121     */
    2222    void notLoggedIn( String reason );
     
    5050     * New private messages were received. See {@link #receivedMessages(boolean, java.util.List)}.
    5151     * 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.
    5253     * @param replace if set, remove all old messages.
    5354     * @param messages list of new private messages.
  • applications/editors/josm/plugins/geochat/src/geochat/GeoChatPanel.java

    r29557 r29558  
    11package geochat;
    22
    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;
     3import java.awt.*;
     4import java.awt.event.*;
     5import java.awt.geom.Rectangle2D;
    86import java.text.SimpleDateFormat;
    97import java.util.*;
    10 import java.util.logging.*;
     8import java.util.List;
    119import javax.swing.*;
    1210import javax.swing.text.BadLocationException;
     11import javax.swing.text.DefaultCaret;
    1312import javax.swing.text.Document;
    1413import org.openstreetmap.josm.Main;
     14import org.openstreetmap.josm.data.Bounds;
    1515import org.openstreetmap.josm.data.coor.LatLon;
    1616import org.openstreetmap.josm.gui.JosmUserIdentityManager;
     17import org.openstreetmap.josm.gui.MapView;
    1718import org.openstreetmap.josm.gui.dialogs.ToggleDialog;
     19import org.openstreetmap.josm.gui.layer.MapViewPaintable;
     20import org.openstreetmap.josm.tools.GBC;
    1821import static org.openstreetmap.josm.tools.I18n.tr;
    1922import static org.openstreetmap.josm.tools.I18n.trn;
     23import org.openstreetmap.josm.tools.ImageProvider;
    2024
    2125/**
     
    2327 * @author zverik
    2428 */
    25 public class GeoChatPanel extends ToggleDialog implements ChatServerConnectionListener {
    26 
    27     private JTextPane chatPane;
     29public class GeoChatPanel extends ToggleDialog implements ChatServerConnectionListener, MapViewPaintable {
     30    private static final String PUBLIC_PANE = "Public Pane";
     31
    2832    private JTextField input;
    2933    private JTabbedPane tabs;
     
    3337    private ChatServerConnection connection;
    3438    private Map<String, LatLon> users;
     39    private Map<String, ChatLogEntry> chatPanes;
    3540   
    3641    public GeoChatPanel() {
    3742        super(tr("GeoChat"), "geochat", tr("Open GeoChat panel"), null, 200, true);
    3843
    39         chatPane = new JTextPane();
    40         chatPane.setEditable(false);
    41         Font font = chatPane.getFont();
    42         chatPane.setFont(font.deriveFont(font.getSize2D() - 2));
    43 
    4444        noData = new JLabel(tr("Zoom in to see messages"), SwingConstants.CENTER);
    4545
     46        chatPanes = new HashMap<String, ChatLogEntry>();
    4647        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        });
    4860
    4961        input = new JPanelTextField() {
    5062            @Override
    5163            protected void processEnter( String text ) {
    52                 connection.postMessage(text);
     64                connection.postMessage(text, getRecipient());
    5365            }
    5466
     
    7890            }
    7991        });
    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));
    86100
    87101        gcPanel = new JPanel(new BorderLayout());
     
    89103        createLayout(gcPanel, false, null);
    90104
    91         users = new HashMap<String, LatLon>();
     105        users = new TreeMap<String, LatLon>();
    92106        // Start threads
    93107        connection = ChatServerConnection.getInstance();
     
    95109        connection.checkLogin();
    96110    }
    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();
    100136        try {
    101137            doc.insertString(doc.getLength(), line, null);
     
    105141    }
    106142
     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
    107214    private String cachedTitle = "";
    108215    private int cachedAlarm = 0;
    109216
     217    @Override
    110218    public void setTitle( String title ) {
    111219        setTitle(title, -1);
     
    125233    }
    126234
     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
    127260    public void loggedIn( String userName ) {
    128261        if( gcPanel.getComponentCount() == 1 ) {
     
    133266    }
    134267
    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        });
    140290    }
    141291
    142292    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);
    144295        repaint();
    145296    }
    146297
    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()));
    158308        // 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        }
    160322    }
    161323
    162324    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
    163332    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();
    168346        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        }
    177351    }
    178352
     
    206380        protected String autoComplete( String word ) { return word; }
    207381    }
     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    }
    208460}
  • applications/editors/josm/plugins/geochat/src/geochat/JsonQueryUtil.java

    r29541 r29558  
    2929            String serverURL = Main.pref.get("geochat.server", "http://zverik.dev.openstreetmap.org/osmochat.php?action=");
    3030            URL url = new URL(serverURL + query);
    31 //            System.out.println("GeoChat URL = " + url.toString());
     31            System.out.println("GeoChat URL = " + url.toString());
    3232            HttpURLConnection connection = (HttpURLConnection)url.openConnection();
    3333            connection.connect();
Note: See TracChangeset for help on using the changeset viewer.