Index: /applications/editors/josm/plugins/geochat/build.xml
===================================================================
--- /applications/editors/josm/plugins/geochat/build.xml	(revision 33795)
+++ /applications/editors/josm/plugins/geochat/build.xml	(revision 33796)
@@ -5,5 +5,5 @@
     <property name="commit.message" value="[josm_geochat] copypaste from keyboard, font size advanced parameters"/>
     <!-- enter the *lowest* JOSM version this plugin is currently compatible with -->
-    <property name="plugin.main.version" value="12743"/>
+    <property name="plugin.main.version" value="12840"/>
 
     <property name="plugin.author" value="Ilya Zverev"/>
Index: /applications/editors/josm/plugins/geochat/src/geochat/ChatPaneManager.java
===================================================================
--- /applications/editors/josm/plugins/geochat/src/geochat/ChatPaneManager.java	(revision 33795)
+++ /applications/editors/josm/plugins/geochat/src/geochat/ChatPaneManager.java	(revision 33796)
@@ -32,237 +32,237 @@
  */
 class ChatPaneManager {
-	private static final String PUBLIC_PANE = "Public Pane";
-
-	private GeoChatPanel panel;
-	private JTabbedPane tabs;
-	private Map<String, ChatPane> chatPanes;
-	private boolean collapsed;
-
-	ChatPaneManager(GeoChatPanel panel, JTabbedPane tabs) {
-		this.panel = panel;
-		this.tabs = tabs;
-		this.collapsed = panel.isDialogInCollapsedView();
-		chatPanes = new HashMap<>();
-		createChatPane(null);
-		tabs.addChangeListener(new ChangeListener() {
-			@Override
-			public void stateChanged(ChangeEvent e) {
-				updateActiveTabStatus();
-			}
-		});
-	}
-
-	public void setCollapsed(boolean collapsed) {
-		this.collapsed = collapsed;
-		updateActiveTabStatus();
-	}
-
-	public boolean hasUser(String user) {
-		return chatPanes.containsKey(user == null ? PUBLIC_PANE : user);
-	}
-
-	public Component getPublicChatComponent() {
-		return chatPanes.get(PUBLIC_PANE).component;
-	}
-
-	public int getNotifyLevel() {
-		int alarm = 0;
-		for (ChatPane entry : chatPanes.values()) {
-			if (entry.notify > alarm)
-				alarm = entry.notify;
-		}
-		return alarm;
-	}
-
-	public void updateActiveTabStatus() {
-		if (tabs.getSelectedIndex() >= 0)
-			((ChatTabTitleComponent) tabs.getTabComponentAt(tabs.getSelectedIndex())).updateAlarm();
-	}
-
-	public void notify(String user, int alarmLevel) {
-		if (alarmLevel <= 0 || !hasUser(user))
-			return;
-		ChatPane entry = chatPanes.get(user == null ? PUBLIC_PANE : user);
-		entry.notify = alarmLevel;
-		int idx = tabs.indexOfComponent(entry.component);
-		if (idx >= 0)
-			((ChatTabTitleComponent) tabs.getTabComponentAt(idx)).updateAlarm();
-	}
-
-	public static int MESSAGE_TYPE_DEFAULT = 0;
-	public static int MESSAGE_TYPE_INFORMATION = 1;
-	public static int MESSAGE_TYPE_ATTENTION = 2;
-	private static Color COLOR_ATTENTION = new Color(0, 0, 192);
-
-	private void addLineToChatPane(String userName, String line, final int messageType) {
-		if (line.length() == 0)
-			return;
-		if (!chatPanes.containsKey(userName))
-			createChatPane(userName);
-		final String nline = line.startsWith("\n") ? line : "\n" + line;
-		final JTextPane thepane = chatPanes.get(userName).pane;
-		GuiHelper.runInEDT(new Runnable() {
-			@Override
-			public void run() {
-				Document doc = thepane.getDocument();
-				try {
-					SimpleAttributeSet attrs = null;
-					if (messageType != MESSAGE_TYPE_DEFAULT) {
-						attrs = new SimpleAttributeSet();
-						if (messageType == MESSAGE_TYPE_INFORMATION)
-							StyleConstants.setItalic(attrs, true);
-						else if (messageType == MESSAGE_TYPE_ATTENTION)
-							StyleConstants.setForeground(attrs, COLOR_ATTENTION);
-					}
-					doc.insertString(doc.getLength(), nline, attrs);
-				} catch (BadLocationException ex) {
-					Logging.warn(ex);
-				}
-				thepane.setCaretPosition(doc.getLength());
-			}
-		});
-	}
-
-	public void addLineToChatPane(String userName, String line) {
-		addLineToChatPane(userName, line, MESSAGE_TYPE_DEFAULT);
-	}
-
-	public void addLineToPublic(String line) {
-		addLineToChatPane(PUBLIC_PANE, line);
-	}
-
-	public void addLineToPublic(String line, int messageType) {
-		addLineToChatPane(PUBLIC_PANE, line, messageType);
-	}
-
-	public void clearPublicChatPane() {
-		chatPanes.get(PUBLIC_PANE).pane.setText("");
-	}
-
-	public void clearChatPane(String userName) {
-		if (userName == null || userName.equals(PUBLIC_PANE))
-			clearPublicChatPane();
-		else
-			chatPanes.get(userName).pane.setText("");
-	}
-
-	public void clearActiveChatPane() {
-		clearChatPane(getActiveChatPane());
-	}
-
-	public ChatPane createChatPane(String userName) {
-		JTextPane chatPane = new JTextPane();
-		chatPane.setEditable(false);
-		Font font = chatPane.getFont();
-		float size = Main.pref.getInteger("geochat.fontsize", -1);
-		if (size < 6)
-			size += font.getSize2D();
-		chatPane.setFont(font.deriveFont(size));
-		//        DefaultCaret caret = (DefaultCaret)chatPane.getCaret(); // does not work
-		//        caret.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE);
-		JScrollPane scrollPane = new JScrollPane(chatPane, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
-		chatPane.addMouseListener(new GeoChatPopupAdapter(panel));
-
-		ChatPane entry = new ChatPane();
-		entry.pane = chatPane;
-		entry.component = scrollPane;
-		entry.notify = 0;
-		entry.userName = userName;
-		entry.isPublic = userName == null;
-		chatPanes.put(userName == null ? PUBLIC_PANE : userName, entry);
-
-		tabs.addTab(null, scrollPane);
-		tabs.setTabComponentAt(tabs.getTabCount() - 1, new ChatTabTitleComponent(entry));
-		tabs.setSelectedComponent(scrollPane);
-		return entry;
-	}
-
-	/**
-	 * Returns key in chatPanes hash map for the currently active
-	 * chat pane, or null in case of an error.
-	 */
-	public String getActiveChatPane() {
-		Component c = tabs.getSelectedComponent();
-		if (c == null)
-			return null;
-		for (String user : chatPanes.keySet()) {
-			if (c.equals(chatPanes.get(user).component))
-				return user;
-		}
-		return null;
-	}
-
-	public String getRecipient() {
-		String user = getActiveChatPane();
-		return user == null || user.equals(PUBLIC_PANE) ? null : user;
-	}
-
-	public void closeChatPane(String user) {
-		if (user == null || user.equals(PUBLIC_PANE) || !chatPanes.containsKey(user))
-			return;
-		tabs.remove(chatPanes.get(user).component);
-		chatPanes.remove(user);
-	}
-
-	public void closeSelectedPrivatePane() {
-		String pane = getRecipient();
-		if (pane != null)
-			closeChatPane(pane);
-	}
-
-	public void closePrivateChatPanes() {
-		List<String> entries = new ArrayList<>(chatPanes.keySet());
-		for (String user : entries) {
-			if (!user.equals(PUBLIC_PANE))
-				closeChatPane(user);
-		}
-	}
-
-	public boolean hasSelectedText() {
-		String user = getActiveChatPane();
-		if (user != null) {
-			JTextPane pane = chatPanes.get(user).pane;
-			return pane.getSelectedText() != null;
-		}
-		return false;
-	}
-
-	public void copySelectedText() {
-		String user = getActiveChatPane();
-		if (user != null)
-			chatPanes.get(user).pane.copy();
-	}
-
-	private class ChatTabTitleComponent extends JLabel {
-		private ChatPane entry;
-
-		ChatTabTitleComponent(ChatPane entry) {
-			super(entry.isPublic ? tr("Public") : entry.userName);
-			this.entry = entry;
-		}
-
-		private Font normalFont;
-		private Font boldFont;
-
-		public void updateAlarm() {
-			if (normalFont == null) {
-				// prepare cached fonts
-				normalFont = getFont().deriveFont(Font.PLAIN);
-				boldFont = getFont().deriveFont(Font.BOLD);
-			}
-			if (entry.notify > 0 && !collapsed && tabs.getSelectedIndex() == tabs.indexOfComponent(entry.component))
-				entry.notify = 0;
-			setFont(entry.notify > 0 ? boldFont : normalFont);
-			panel.updateTitleAlarm();
-		}
-	}
-
-	static class ChatPane {
-		public String userName;
-		public boolean isPublic;
-		public JTextPane pane;
-		public JScrollPane component;
-		public int notify;
-
-	}
+    private static final String PUBLIC_PANE = "Public Pane";
+
+    private GeoChatPanel panel;
+    private JTabbedPane tabs;
+    private Map<String, ChatPane> chatPanes;
+    private boolean collapsed;
+
+    ChatPaneManager(GeoChatPanel panel, JTabbedPane tabs) {
+        this.panel = panel;
+        this.tabs = tabs;
+        this.collapsed = panel.isDialogInCollapsedView();
+        chatPanes = new HashMap<>();
+        createChatPane(null);
+        tabs.addChangeListener(new ChangeListener() {
+            @Override
+            public void stateChanged(ChangeEvent e) {
+                updateActiveTabStatus();
+            }
+        });
+    }
+
+    public void setCollapsed(boolean collapsed) {
+        this.collapsed = collapsed;
+        updateActiveTabStatus();
+    }
+
+    public boolean hasUser(String user) {
+        return chatPanes.containsKey(user == null ? PUBLIC_PANE : user);
+    }
+
+    public Component getPublicChatComponent() {
+        return chatPanes.get(PUBLIC_PANE).component;
+    }
+
+    public int getNotifyLevel() {
+        int alarm = 0;
+        for (ChatPane entry : chatPanes.values()) {
+            if (entry.notify > alarm)
+                alarm = entry.notify;
+        }
+        return alarm;
+    }
+
+    public void updateActiveTabStatus() {
+        if (tabs.getSelectedIndex() >= 0)
+            ((ChatTabTitleComponent) tabs.getTabComponentAt(tabs.getSelectedIndex())).updateAlarm();
+    }
+
+    public void notify(String user, int alarmLevel) {
+        if (alarmLevel <= 0 || !hasUser(user))
+            return;
+        ChatPane entry = chatPanes.get(user == null ? PUBLIC_PANE : user);
+        entry.notify = alarmLevel;
+        int idx = tabs.indexOfComponent(entry.component);
+        if (idx >= 0)
+            ((ChatTabTitleComponent) tabs.getTabComponentAt(idx)).updateAlarm();
+    }
+
+    public static int MESSAGE_TYPE_DEFAULT = 0;
+    public static int MESSAGE_TYPE_INFORMATION = 1;
+    public static int MESSAGE_TYPE_ATTENTION = 2;
+    private static Color COLOR_ATTENTION = new Color(0, 0, 192);
+
+    private void addLineToChatPane(String userName, String line, final int messageType) {
+        if (line.length() == 0)
+            return;
+        if (!chatPanes.containsKey(userName))
+            createChatPane(userName);
+        final String nline = line.startsWith("\n") ? line : "\n" + line;
+        final JTextPane thepane = chatPanes.get(userName).pane;
+        GuiHelper.runInEDT(new Runnable() {
+            @Override
+            public void run() {
+                Document doc = thepane.getDocument();
+                try {
+                    SimpleAttributeSet attrs = null;
+                    if (messageType != MESSAGE_TYPE_DEFAULT) {
+                        attrs = new SimpleAttributeSet();
+                        if (messageType == MESSAGE_TYPE_INFORMATION)
+                            StyleConstants.setItalic(attrs, true);
+                        else if (messageType == MESSAGE_TYPE_ATTENTION)
+                            StyleConstants.setForeground(attrs, COLOR_ATTENTION);
+                    }
+                    doc.insertString(doc.getLength(), nline, attrs);
+                } catch (BadLocationException ex) {
+                    Logging.warn(ex);
+                }
+                thepane.setCaretPosition(doc.getLength());
+            }
+        });
+    }
+
+    public void addLineToChatPane(String userName, String line) {
+        addLineToChatPane(userName, line, MESSAGE_TYPE_DEFAULT);
+    }
+
+    public void addLineToPublic(String line) {
+        addLineToChatPane(PUBLIC_PANE, line);
+    }
+
+    public void addLineToPublic(String line, int messageType) {
+        addLineToChatPane(PUBLIC_PANE, line, messageType);
+    }
+
+    public void clearPublicChatPane() {
+        chatPanes.get(PUBLIC_PANE).pane.setText("");
+    }
+
+    public void clearChatPane(String userName) {
+        if (userName == null || userName.equals(PUBLIC_PANE))
+            clearPublicChatPane();
+        else
+            chatPanes.get(userName).pane.setText("");
+    }
+
+    public void clearActiveChatPane() {
+        clearChatPane(getActiveChatPane());
+    }
+
+    public ChatPane createChatPane(String userName) {
+        JTextPane chatPane = new JTextPane();
+        chatPane.setEditable(false);
+        Font font = chatPane.getFont();
+        float size = Main.pref.getInt("geochat.fontsize", -1);
+        if (size < 6)
+            size += font.getSize2D();
+        chatPane.setFont(font.deriveFont(size));
+        //        DefaultCaret caret = (DefaultCaret)chatPane.getCaret(); // does not work
+        //        caret.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE);
+        JScrollPane scrollPane = new JScrollPane(chatPane, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
+        chatPane.addMouseListener(new GeoChatPopupAdapter(panel));
+
+        ChatPane entry = new ChatPane();
+        entry.pane = chatPane;
+        entry.component = scrollPane;
+        entry.notify = 0;
+        entry.userName = userName;
+        entry.isPublic = userName == null;
+        chatPanes.put(userName == null ? PUBLIC_PANE : userName, entry);
+
+        tabs.addTab(null, scrollPane);
+        tabs.setTabComponentAt(tabs.getTabCount() - 1, new ChatTabTitleComponent(entry));
+        tabs.setSelectedComponent(scrollPane);
+        return entry;
+    }
+
+    /**
+     * Returns key in chatPanes hash map for the currently active
+     * chat pane, or null in case of an error.
+     */
+    public String getActiveChatPane() {
+        Component c = tabs.getSelectedComponent();
+        if (c == null)
+            return null;
+        for (String user : chatPanes.keySet()) {
+            if (c.equals(chatPanes.get(user).component))
+                return user;
+        }
+        return null;
+    }
+
+    public String getRecipient() {
+        String user = getActiveChatPane();
+        return user == null || user.equals(PUBLIC_PANE) ? null : user;
+    }
+
+    public void closeChatPane(String user) {
+        if (user == null || user.equals(PUBLIC_PANE) || !chatPanes.containsKey(user))
+            return;
+        tabs.remove(chatPanes.get(user).component);
+        chatPanes.remove(user);
+    }
+
+    public void closeSelectedPrivatePane() {
+        String pane = getRecipient();
+        if (pane != null)
+            closeChatPane(pane);
+    }
+
+    public void closePrivateChatPanes() {
+        List<String> entries = new ArrayList<>(chatPanes.keySet());
+        for (String user : entries) {
+            if (!user.equals(PUBLIC_PANE))
+                closeChatPane(user);
+        }
+    }
+
+    public boolean hasSelectedText() {
+        String user = getActiveChatPane();
+        if (user != null) {
+            JTextPane pane = chatPanes.get(user).pane;
+            return pane.getSelectedText() != null;
+        }
+        return false;
+    }
+
+    public void copySelectedText() {
+        String user = getActiveChatPane();
+        if (user != null)
+            chatPanes.get(user).pane.copy();
+    }
+
+    private class ChatTabTitleComponent extends JLabel {
+        private ChatPane entry;
+
+        ChatTabTitleComponent(ChatPane entry) {
+            super(entry.isPublic ? tr("Public") : entry.userName);
+            this.entry = entry;
+        }
+
+        private Font normalFont;
+        private Font boldFont;
+
+        public void updateAlarm() {
+            if (normalFont == null) {
+                // prepare cached fonts
+                normalFont = getFont().deriveFont(Font.PLAIN);
+                boldFont = getFont().deriveFont(Font.BOLD);
+            }
+            if (entry.notify > 0 && !collapsed && tabs.getSelectedIndex() == tabs.indexOfComponent(entry.component))
+                entry.notify = 0;
+            setFont(entry.notify > 0 ? boldFont : normalFont);
+            panel.updateTitleAlarm();
+        }
+    }
+
+    static class ChatPane {
+        public String userName;
+        public boolean isPublic;
+        public JTextPane pane;
+        public JScrollPane component;
+        public int notify;
+
+    }
 }
Index: /applications/editors/josm/plugins/geochat/src/geochat/ChatServerConnection.java
===================================================================
--- /applications/editors/josm/plugins/geochat/src/geochat/ChatServerConnection.java	(revision 33795)
+++ /applications/editors/josm/plugins/geochat/src/geochat/ChatServerConnection.java	(revision 33796)
@@ -20,6 +20,6 @@
 
 import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.data.coor.CoordinateFormat;
 import org.openstreetmap.josm.data.coor.LatLon;
+import org.openstreetmap.josm.data.coor.conversion.DecimalDegreesCoordinateFormat;
 import org.openstreetmap.josm.data.projection.Projection;
 import org.openstreetmap.josm.gui.MainApplication;
@@ -88,5 +88,5 @@
      */
     public void autoLogin(final String userName) {
-        final int uid = Main.pref.getInteger("geochat.lastuid", 0);
+        final int uid = Main.pref.getInt("geochat.lastuid", 0);
         if (uid <= 0) {
             if (userName != null && userName.length() > 1)
@@ -147,6 +147,6 @@
         try {
             String nameAttr = token != null ? "&token=" + token : "&name=" + URLEncoder.encode(userName, "UTF-8");
-            String query = "register&lat=" + pos.latToString(CoordinateFormat.DECIMAL_DEGREES)
-            + "&lon=" + pos.lonToString(CoordinateFormat.DECIMAL_DEGREES)
+            String query = "register&lat=" + DecimalDegreesCoordinateFormat.INSTANCE.latToString(pos)
+            + "&lon=" + DecimalDegreesCoordinateFormat.INSTANCE.lonToString(pos)
             + nameAttr;
             JsonQueryUtil.queryAsync(query, new JsonQueryCallback() {
@@ -173,5 +173,5 @@
         this.userId = userId;
         this.userName = userName;
-        Main.pref.putInteger("geochat.lastuid", userId);
+        Main.pref.putInt("geochat.lastuid", userId);
         for (ChatServerConnectionListener listener : listeners) {
             listener.loggedIn(userName);
@@ -252,6 +252,6 @@
         }
         try {
-            String query = "post&lat=" + pos.latToString(CoordinateFormat.DECIMAL_DEGREES)
-            + "&lon=" + pos.lonToString(CoordinateFormat.DECIMAL_DEGREES)
+            String query = "post&lat=" + DecimalDegreesCoordinateFormat.INSTANCE.latToString(pos)
+            + "&lon=" + DecimalDegreesCoordinateFormat.INSTANCE.lonToString(pos)
             + "&uid=" + userId
             + "&message=" + URLEncoder.encode(message, "UTF8");
@@ -329,5 +329,5 @@
         public void run() {
             //            lastId = Main.pref.getLong("geochat.lastid", 0);
-            int interval = Main.pref.getInteger("geochat.interval", 2);
+            int interval = Main.pref.getInt("geochat.interval", 2);
             while (!stopping) {
                 process();
@@ -369,6 +369,6 @@
             lastPosition = pos;
 
-            String query = "get&lat=" + pos.latToString(CoordinateFormat.DECIMAL_DEGREES)
-            + "&lon=" + pos.lonToString(CoordinateFormat.DECIMAL_DEGREES)
+            String query = "get&lat=" + DecimalDegreesCoordinateFormat.INSTANCE.latToString(pos)
+            + "&lon=" + DecimalDegreesCoordinateFormat.INSTANCE.lonToString(pos)
             + "&uid=" + userId + "&last=" + lastId;
             JsonObject json;
Index: /applications/editors/josm/plugins/geochat/src/geochat/GeoChatPanel.java
===================================================================
--- /applications/editors/josm/plugins/geochat/src/geochat/GeoChatPanel.java	(revision 33795)
+++ /applications/editors/josm/plugins/geochat/src/geochat/GeoChatPanel.java	(revision 33796)
@@ -53,348 +53,348 @@
  */
 public class GeoChatPanel extends ToggleDialog implements ChatServerConnectionListener, MapViewPaintable {
-	private JTextField input;
-	private JTabbedPane tabs;
-	private JComponent noData;
-	private JPanel loginPanel;
-	private JPanel gcPanel;
-	private ChatServerConnection connection;
-	// those fields should be visible to popup menu actions
-	Map<String, LatLon> users;
-	ChatPaneManager chatPanes;
-	boolean userLayerActive;
-
-	public GeoChatPanel() {
-		super(tr("GeoChat"), "geochat", tr("Open GeoChat panel"), null, 200, true);
-
-		noData = new JLabel(tr("Zoom in to see messages"), SwingConstants.CENTER);
-
-		tabs = new JTabbedPane();
-		tabs.addMouseListener(new GeoChatPopupAdapter(this));
-		chatPanes = new ChatPaneManager(this, tabs);
-
-		input = new JPanelTextField() {
-			@Override
-			protected void processEnter(String text) {
-				connection.postMessage(text, chatPanes.getRecipient());
-			}
-
-			@Override
-			protected String autoComplete(String word, boolean atStart) {
-				return autoCompleteUser(word, atStart);
-			}
-		};
-
-		String defaultUserName = constructUserName();
-		loginPanel = createLoginPanel(defaultUserName);
-
-		gcPanel = new JPanel(new BorderLayout());
-		gcPanel.add(loginPanel, BorderLayout.CENTER);
-		createLayout(gcPanel, false, null);
-
-		users = new TreeMap<>();
-		// Start threads
-		connection = ChatServerConnection.getInstance();
-		connection.addListener(this);
-		boolean autoLogin = Main.pref.get("geochat.username", null) == null ? false : Main.pref.getBoolean("geochat.autologin", true);
-		connection.autoLoginWithDelay(autoLogin ? defaultUserName : null);
-		updateTitleAlarm();
-	}
-
-	private String constructUserName() {
-		String userName = Main.pref.get("geochat.username", null); // so the default is null
-		if (userName == null)
-			userName = UserIdentityManager.getInstance().getUserName();
-		if (userName == null)
-			userName = "";
-		if (userName.contains("@"))
-			userName = userName.substring(0, userName.indexOf('@'));
-		userName = userName.replace(' ', '_');
-		return userName;
-	}
-
-	private JPanel createLoginPanel(String defaultUserName) {
-		final JTextField nameField = new JPanelTextField() {
-			@Override
-			protected void processEnter(String text) {
-				connection.login(text);
-			}
-		};
-		nameField.setText(defaultUserName);
-
-		JButton loginButton = new JButton(tr("Login"));
-		loginButton.addActionListener(new ActionListener() {
-			@Override
-			public void actionPerformed(ActionEvent e) {
-				connection.login(nameField.getText());
-			}
-		});
-		nameField.setPreferredSize(new Dimension(nameField.getPreferredSize().width, loginButton.getPreferredSize().height));
-
-		final JCheckBox autoLoginBox = new JCheckBox(tr("Enable autologin"), Main.pref.getBoolean("geochat.autologin", true));
-		autoLoginBox.addActionListener(new ActionListener() {
-			@Override
-			public void actionPerformed(ActionEvent e) {
-				Main.pref.put("geochat.autologin", autoLoginBox.isSelected());
-			}
-		});
-
-		JPanel panel = new JPanel(new GridBagLayout());
-		panel.add(nameField, GBC.std().fill(GridBagConstraints.HORIZONTAL).insets(15, 0, 5, 0));
-		panel.add(loginButton, GBC.eol().fill(GridBagConstraints.NONE).insets(0, 0, 15, 0));
-		panel.add(autoLoginBox, GBC.std().insets(15, 0, 15, 0));
-		return panel;
-	}
-
-	protected void logout() {
-		connection.logout();
-	}
-
-	@Override
-	public void destroy() {
-		try {
-			if (Main.pref.getBoolean("geochat.logout.on.close", true)) {
-				connection.removeListener(this);
-				connection.bruteLogout();
-			}
-		} catch (IOException e) {
-			Logging.warn("Failed to logout from geochat server: " + e.getMessage());
-		}
-		super.destroy();
-	}
-
-	private String autoCompleteUser(String word, boolean atStart) {
-		String result = null;
-		boolean singleUser = true;
-		for (String user : users.keySet()) {
-			if (user.startsWith(word)) {
-				if (result == null)
-					result = user;
-				else {
-					singleUser = false;
-					int i = word.length();
-					while (i < result.length() && i < user.length() && result.charAt(i) == user.charAt(i)) {
-						i++;
-					}
-					if (i < result.length())
-						result = result.substring(0, i);
-				}
-			}
-		}
-		return result == null ? null : !singleUser ? result : atStart ? result + ": " : result + " ";
-	}
-
-	/**
-	 * This is implementation of a "temporary layer". It paints circles
-	 * for all users nearby.
-	 */
-	@Override
-	public void paint(Graphics2D g, MapView mv, Bounds bbox) {
-		Graphics2D g2d = (Graphics2D) g.create();
-		g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
-		Composite ac04 = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.4f);
-		Composite ac10 = g2d.getComposite();
-
-		Font font = g2d.getFont().deriveFont(Font.BOLD, g2d.getFont().getSize2D() + 2.0f);
-		g2d.setFont(font);
-		FontMetrics fm = g2d.getFontMetrics();
-
-		for (String user : users.keySet()) {
-			int stringWidth = fm.stringWidth(user);
-			int radius = stringWidth / 2 + 10;
-			Point p = mv.getPoint(users.get(user));
-
-			g2d.setComposite(ac04);
-			g2d.setColor(Color.white);
-			g2d.fillOval(p.x - radius, p.y - radius, radius * 2 + 1, radius * 2 + 1);
-
-			g2d.setComposite(ac10);
-			g2d.setColor(Color.black);
-			g2d.drawString(user, p.x - stringWidth / 2, p.y + fm.getDescent());
-		}
-	}
-
-	/* ================== Notifications in the title ======================= */
-
-	/**
-	 * Display number of users and notifications in the panel title.
-	 */
-	protected void updateTitleAlarm() {
-		int alarmLevel = connection.isLoggedIn() ? chatPanes.getNotifyLevel() : 0;
-		if (!isDialogInCollapsedView() && alarmLevel > 1)
-			alarmLevel = 1;
-
-		String comment;
-		if (connection.isLoggedIn()) {
-			comment = trn("{0} user", "{0} users", users.size() + 1, users.size() + 1);
-		} else {
-			comment = tr("not logged in");
-		}
-
-		String title = tr("GeoChat");
-		if (comment != null)
-			title = title + " (" + comment + ")";
-		final String alarm = (alarmLevel <= 0 ? "" : alarmLevel == 1 ? "* " : "!!! ") + title;
-		GuiHelper.runInEDT(new Runnable() {
-			@Override
-			public void run() {
-				setTitle(alarm);
-			}
-		});
-	}
-
-	/**
-	 * Track panel collapse events.
-	 */
-	@Override
-	protected void setIsCollapsed(boolean val) {
-		super.setIsCollapsed(val);
-		chatPanes.setCollapsed(val);
-		updateTitleAlarm();
-	}
-
-	/* ============ ChatServerConnectionListener methods ============= */
-
-	@Override
-	public void loggedIn(String userName) {
-		Main.pref.put("geochat.username", userName);
-		if (gcPanel.getComponentCount() == 1) {
-			GuiHelper.runInEDTAndWait(new Runnable() {
-				@Override
-				public void run() {
-					gcPanel.remove(0);
-					gcPanel.add(tabs, BorderLayout.CENTER);
-					gcPanel.add(input, BorderLayout.SOUTH);
-				}
-			});
-		}
-		updateTitleAlarm();
-	}
-
-	@Override
-	public void notLoggedIn(final String reason) {
-		if (reason != null) {
-			GuiHelper.runInEDT(new Runnable() {
-				@Override
-				public void run() {
-					new Notification(tr("Failed to log in to GeoChat:") + "\n" + reason).show();
-				}
-			});
-		} else {
-			// regular logout
-			if (gcPanel.getComponentCount() > 1) {
-				gcPanel.removeAll();
-				gcPanel.add(loginPanel, BorderLayout.CENTER);
-			}
-		}
-		updateTitleAlarm();
-	}
-
-	@Override
-	public void messageSendFailed(final String reason) {
-		GuiHelper.runInEDT(new Runnable() {
-			@Override
-			public void run() {
-				new Notification(tr("Failed to send message:") + "\n" + reason).show();
-			}
-		});
-	}
-
-	@Override
-	public void statusChanged(boolean active) {
-		// only the public tab, because private chats don't rely on coordinates
-		tabs.setComponentAt(0, active ? chatPanes.getPublicChatComponent() : noData);
-		repaint();
-	}
-
-	@Override
-	public void updateUsers(Map<String, LatLon> newUsers) {
-		for (String uname : this.users.keySet()) {
-			if (!newUsers.containsKey(uname))
-				chatPanes.addLineToPublic(tr("User {0} has left", uname), ChatPaneManager.MESSAGE_TYPE_INFORMATION);
-		}
-		for (String uname : newUsers.keySet()) {
-			if (!this.users.containsKey(uname))
-				chatPanes.addLineToPublic(tr("User {0} is mapping nearby", uname), ChatPaneManager.MESSAGE_TYPE_INFORMATION);
-		}
-		this.users = newUsers;
-		updateTitleAlarm();
-		if (userLayerActive && MainApplication.isDisplayingMapView())
-			MainApplication.getMap().mapView.repaint();
-	}
-
-	private final SimpleDateFormat TIME_FORMAT = new SimpleDateFormat("HH:mm");
-
-	private void formatMessage(StringBuilder sb, ChatMessage msg) {
-		sb.append("\n");
-		sb.append('[').append(TIME_FORMAT.format(msg.getTime())).append("] ");
-		sb.append(msg.getAuthor()).append(": ").append(msg.getMessage());
-	}
-
-	@Override
-	public void receivedMessages(boolean replace, List<ChatMessage> messages) {
-		if (replace)
-			chatPanes.clearPublicChatPane();
-		if (!messages.isEmpty()) {
-			int alarm = 0;
-			StringBuilder sb = new StringBuilder();
-			for (ChatMessage msg : messages) {
-				boolean important = msg.isIncoming() && containsName(msg.getMessage());
-				if (msg.isIncoming() && alarm < 2) {
-					alarm = important ? 2 : 1;
-				}
-				if (important) {
-					// add buffer, then add current line with italic, then clear buffer
-					chatPanes.addLineToPublic(sb.toString());
-					sb.setLength(0);
-					formatMessage(sb, msg);
-					chatPanes.addLineToPublic(sb.toString(), ChatPaneManager.MESSAGE_TYPE_ATTENTION);
-					sb.setLength(0);
-				} else
-					formatMessage(sb, msg);
-			}
-			chatPanes.addLineToPublic(sb.toString());
-			if (alarm > 0)
-				chatPanes.notify(null, alarm);
-		}
-		if (replace)
-			showNearbyUsers();
-	}
-
-	private void showNearbyUsers() {
-		if (!users.isEmpty()) {
-			StringBuilder sb = new StringBuilder(tr("Users mapping nearby:"));
-			boolean first = true;
-			for (String user : users.keySet()) {
-				sb.append(first ? " " : ", ");
-				sb.append(user);
-			}
-			chatPanes.addLineToPublic(sb.toString(), ChatPaneManager.MESSAGE_TYPE_INFORMATION);
-		}
-	}
-
-	private boolean containsName(String message) {
-		String userName = connection.getUserName();
-		int length = userName.length();
-		int i = message.indexOf(userName);
-		while (i >= 0) {
-			if ((i == 0 || !Character.isJavaIdentifierPart(message.charAt(i - 1)))
-					&& (i + length >= message.length() || !Character.isJavaIdentifierPart(message.charAt(i + length))))
-				return true;
-			i = message.indexOf(userName, i + 1);
-		}
-		return false;
-	}
-
-	@Override
-	public void receivedPrivateMessages(boolean replace, List<ChatMessage> messages) {
-		if (replace)
-			chatPanes.closePrivateChatPanes();
-		for (ChatMessage msg : messages) {
-			StringBuilder sb = new StringBuilder();
-			formatMessage(sb, msg);
-			chatPanes.addLineToChatPane(msg.isIncoming() ? msg.getAuthor() : msg.getRecipient(), sb.toString());
-			if (msg.isIncoming())
-				chatPanes.notify(msg.getAuthor(), 2);
-		}
-	}
+    private JTextField input;
+    private JTabbedPane tabs;
+    private JComponent noData;
+    private JPanel loginPanel;
+    private JPanel gcPanel;
+    private ChatServerConnection connection;
+    // those fields should be visible to popup menu actions
+    Map<String, LatLon> users;
+    ChatPaneManager chatPanes;
+    boolean userLayerActive;
+
+    public GeoChatPanel() {
+        super(tr("GeoChat"), "geochat", tr("Open GeoChat panel"), null, 200, true);
+
+        noData = new JLabel(tr("Zoom in to see messages"), SwingConstants.CENTER);
+
+        tabs = new JTabbedPane();
+        tabs.addMouseListener(new GeoChatPopupAdapter(this));
+        chatPanes = new ChatPaneManager(this, tabs);
+
+        input = new JPanelTextField() {
+            @Override
+            protected void processEnter(String text) {
+                connection.postMessage(text, chatPanes.getRecipient());
+            }
+
+            @Override
+            protected String autoComplete(String word, boolean atStart) {
+                return autoCompleteUser(word, atStart);
+            }
+        };
+
+        String defaultUserName = constructUserName();
+        loginPanel = createLoginPanel(defaultUserName);
+
+        gcPanel = new JPanel(new BorderLayout());
+        gcPanel.add(loginPanel, BorderLayout.CENTER);
+        createLayout(gcPanel, false, null);
+
+        users = new TreeMap<>();
+        // Start threads
+        connection = ChatServerConnection.getInstance();
+        connection.addListener(this);
+        boolean autoLogin = Main.pref.get("geochat.username", null) == null ? false : Main.pref.getBoolean("geochat.autologin", true);
+        connection.autoLoginWithDelay(autoLogin ? defaultUserName : null);
+        updateTitleAlarm();
+    }
+
+    private String constructUserName() {
+        String userName = Main.pref.get("geochat.username", null); // so the default is null
+        if (userName == null)
+            userName = UserIdentityManager.getInstance().getUserName();
+        if (userName == null)
+            userName = "";
+        if (userName.contains("@"))
+            userName = userName.substring(0, userName.indexOf('@'));
+        userName = userName.replace(' ', '_');
+        return userName;
+    }
+
+    private JPanel createLoginPanel(String defaultUserName) {
+        final JTextField nameField = new JPanelTextField() {
+            @Override
+            protected void processEnter(String text) {
+                connection.login(text);
+            }
+        };
+        nameField.setText(defaultUserName);
+
+        JButton loginButton = new JButton(tr("Login"));
+        loginButton.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                connection.login(nameField.getText());
+            }
+        });
+        nameField.setPreferredSize(new Dimension(nameField.getPreferredSize().width, loginButton.getPreferredSize().height));
+
+        final JCheckBox autoLoginBox = new JCheckBox(tr("Enable autologin"), Main.pref.getBoolean("geochat.autologin", true));
+        autoLoginBox.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                Main.pref.putBoolean("geochat.autologin", autoLoginBox.isSelected());
+            }
+        });
+
+        JPanel panel = new JPanel(new GridBagLayout());
+        panel.add(nameField, GBC.std().fill(GridBagConstraints.HORIZONTAL).insets(15, 0, 5, 0));
+        panel.add(loginButton, GBC.eol().fill(GridBagConstraints.NONE).insets(0, 0, 15, 0));
+        panel.add(autoLoginBox, GBC.std().insets(15, 0, 15, 0));
+        return panel;
+    }
+
+    protected void logout() {
+        connection.logout();
+    }
+
+    @Override
+    public void destroy() {
+        try {
+            if (Main.pref.getBoolean("geochat.logout.on.close", true)) {
+                connection.removeListener(this);
+                connection.bruteLogout();
+            }
+        } catch (IOException e) {
+            Logging.warn("Failed to logout from geochat server: " + e.getMessage());
+        }
+        super.destroy();
+    }
+
+    private String autoCompleteUser(String word, boolean atStart) {
+        String result = null;
+        boolean singleUser = true;
+        for (String user : users.keySet()) {
+            if (user.startsWith(word)) {
+                if (result == null)
+                    result = user;
+                else {
+                    singleUser = false;
+                    int i = word.length();
+                    while (i < result.length() && i < user.length() && result.charAt(i) == user.charAt(i)) {
+                        i++;
+                    }
+                    if (i < result.length())
+                        result = result.substring(0, i);
+                }
+            }
+        }
+        return result == null ? null : !singleUser ? result : atStart ? result + ": " : result + " ";
+    }
+
+    /**
+     * This is implementation of a "temporary layer". It paints circles
+     * for all users nearby.
+     */
+    @Override
+    public void paint(Graphics2D g, MapView mv, Bounds bbox) {
+        Graphics2D g2d = (Graphics2D) g.create();
+        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+        Composite ac04 = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.4f);
+        Composite ac10 = g2d.getComposite();
+
+        Font font = g2d.getFont().deriveFont(Font.BOLD, g2d.getFont().getSize2D() + 2.0f);
+        g2d.setFont(font);
+        FontMetrics fm = g2d.getFontMetrics();
+
+        for (String user : users.keySet()) {
+            int stringWidth = fm.stringWidth(user);
+            int radius = stringWidth / 2 + 10;
+            Point p = mv.getPoint(users.get(user));
+
+            g2d.setComposite(ac04);
+            g2d.setColor(Color.white);
+            g2d.fillOval(p.x - radius, p.y - radius, radius * 2 + 1, radius * 2 + 1);
+
+            g2d.setComposite(ac10);
+            g2d.setColor(Color.black);
+            g2d.drawString(user, p.x - stringWidth / 2, p.y + fm.getDescent());
+        }
+    }
+
+    /* ================== Notifications in the title ======================= */
+
+    /**
+     * Display number of users and notifications in the panel title.
+     */
+    protected void updateTitleAlarm() {
+        int alarmLevel = connection.isLoggedIn() ? chatPanes.getNotifyLevel() : 0;
+        if (!isDialogInCollapsedView() && alarmLevel > 1)
+            alarmLevel = 1;
+
+        String comment;
+        if (connection.isLoggedIn()) {
+            comment = trn("{0} user", "{0} users", users.size() + 1, users.size() + 1);
+        } else {
+            comment = tr("not logged in");
+        }
+
+        String title = tr("GeoChat");
+        if (comment != null)
+            title = title + " (" + comment + ")";
+        final String alarm = (alarmLevel <= 0 ? "" : alarmLevel == 1 ? "* " : "!!! ") + title;
+        GuiHelper.runInEDT(new Runnable() {
+            @Override
+            public void run() {
+                setTitle(alarm);
+            }
+        });
+    }
+
+    /**
+     * Track panel collapse events.
+     */
+    @Override
+    protected void setIsCollapsed(boolean val) {
+        super.setIsCollapsed(val);
+        chatPanes.setCollapsed(val);
+        updateTitleAlarm();
+    }
+
+    /* ============ ChatServerConnectionListener methods ============= */
+
+    @Override
+    public void loggedIn(String userName) {
+        Main.pref.put("geochat.username", userName);
+        if (gcPanel.getComponentCount() == 1) {
+            GuiHelper.runInEDTAndWait(new Runnable() {
+                @Override
+                public void run() {
+                    gcPanel.remove(0);
+                    gcPanel.add(tabs, BorderLayout.CENTER);
+                    gcPanel.add(input, BorderLayout.SOUTH);
+                }
+            });
+        }
+        updateTitleAlarm();
+    }
+
+    @Override
+    public void notLoggedIn(final String reason) {
+        if (reason != null) {
+            GuiHelper.runInEDT(new Runnable() {
+                @Override
+                public void run() {
+                    new Notification(tr("Failed to log in to GeoChat:") + "\n" + reason).show();
+                }
+            });
+        } else {
+            // regular logout
+            if (gcPanel.getComponentCount() > 1) {
+                gcPanel.removeAll();
+                gcPanel.add(loginPanel, BorderLayout.CENTER);
+            }
+        }
+        updateTitleAlarm();
+    }
+
+    @Override
+    public void messageSendFailed(final String reason) {
+        GuiHelper.runInEDT(new Runnable() {
+            @Override
+            public void run() {
+                new Notification(tr("Failed to send message:") + "\n" + reason).show();
+            }
+        });
+    }
+
+    @Override
+    public void statusChanged(boolean active) {
+        // only the public tab, because private chats don't rely on coordinates
+        tabs.setComponentAt(0, active ? chatPanes.getPublicChatComponent() : noData);
+        repaint();
+    }
+
+    @Override
+    public void updateUsers(Map<String, LatLon> newUsers) {
+        for (String uname : this.users.keySet()) {
+            if (!newUsers.containsKey(uname))
+                chatPanes.addLineToPublic(tr("User {0} has left", uname), ChatPaneManager.MESSAGE_TYPE_INFORMATION);
+        }
+        for (String uname : newUsers.keySet()) {
+            if (!this.users.containsKey(uname))
+                chatPanes.addLineToPublic(tr("User {0} is mapping nearby", uname), ChatPaneManager.MESSAGE_TYPE_INFORMATION);
+        }
+        this.users = newUsers;
+        updateTitleAlarm();
+        if (userLayerActive && MainApplication.isDisplayingMapView())
+            MainApplication.getMap().mapView.repaint();
+    }
+
+    private final SimpleDateFormat TIME_FORMAT = new SimpleDateFormat("HH:mm");
+
+    private void formatMessage(StringBuilder sb, ChatMessage msg) {
+        sb.append("\n");
+        sb.append('[').append(TIME_FORMAT.format(msg.getTime())).append("] ");
+        sb.append(msg.getAuthor()).append(": ").append(msg.getMessage());
+    }
+
+    @Override
+    public void receivedMessages(boolean replace, List<ChatMessage> messages) {
+        if (replace)
+            chatPanes.clearPublicChatPane();
+        if (!messages.isEmpty()) {
+            int alarm = 0;
+            StringBuilder sb = new StringBuilder();
+            for (ChatMessage msg : messages) {
+                boolean important = msg.isIncoming() && containsName(msg.getMessage());
+                if (msg.isIncoming() && alarm < 2) {
+                    alarm = important ? 2 : 1;
+                }
+                if (important) {
+                    // add buffer, then add current line with italic, then clear buffer
+                    chatPanes.addLineToPublic(sb.toString());
+                    sb.setLength(0);
+                    formatMessage(sb, msg);
+                    chatPanes.addLineToPublic(sb.toString(), ChatPaneManager.MESSAGE_TYPE_ATTENTION);
+                    sb.setLength(0);
+                } else
+                    formatMessage(sb, msg);
+            }
+            chatPanes.addLineToPublic(sb.toString());
+            if (alarm > 0)
+                chatPanes.notify(null, alarm);
+        }
+        if (replace)
+            showNearbyUsers();
+    }
+
+    private void showNearbyUsers() {
+        if (!users.isEmpty()) {
+            StringBuilder sb = new StringBuilder(tr("Users mapping nearby:"));
+            boolean first = true;
+            for (String user : users.keySet()) {
+                sb.append(first ? " " : ", ");
+                sb.append(user);
+            }
+            chatPanes.addLineToPublic(sb.toString(), ChatPaneManager.MESSAGE_TYPE_INFORMATION);
+        }
+    }
+
+    private boolean containsName(String message) {
+        String userName = connection.getUserName();
+        int length = userName.length();
+        int i = message.indexOf(userName);
+        while (i >= 0) {
+            if ((i == 0 || !Character.isJavaIdentifierPart(message.charAt(i - 1)))
+                    && (i + length >= message.length() || !Character.isJavaIdentifierPart(message.charAt(i + length))))
+                return true;
+            i = message.indexOf(userName, i + 1);
+        }
+        return false;
+    }
+
+    @Override
+    public void receivedPrivateMessages(boolean replace, List<ChatMessage> messages) {
+        if (replace)
+            chatPanes.closePrivateChatPanes();
+        for (ChatMessage msg : messages) {
+            StringBuilder sb = new StringBuilder();
+            formatMessage(sb, msg);
+            chatPanes.addLineToChatPane(msg.isIncoming() ? msg.getAuthor() : msg.getRecipient(), sb.toString());
+            if (msg.isIncoming())
+                chatPanes.notify(msg.getAuthor(), 2);
+        }
+    }
 }
