Index: trunk/src/org/openstreetmap/josm/data/osm/Changeset.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/Changeset.java	(revision 7702)
+++ trunk/src/org/openstreetmap/josm/data/osm/Changeset.java	(revision 7704)
@@ -2,7 +2,10 @@
 package org.openstreetmap.josm.data.osm;
 
+import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.Date;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
@@ -39,10 +42,10 @@
     /** the map of tags */
     private Map<String,String> tags;
-    /** indicates whether this changeset is incomplete. For an
-     * incomplete changeset we only know its id
-     */
+    /** indicates whether this changeset is incomplete. For an incomplete changeset we only know its id */
     private boolean incomplete;
     /** the changeset content */
     private ChangesetDataSet content = null;
+    /** the changeset discussion */
+    private List<ChangesetDiscussionComment> discussion = null;
 
     /**
@@ -328,3 +331,30 @@
         this.content = content;
     }
+
+    /**
+     * Replies the list of comments in the changeset discussion, if any.
+     * @return the list of comments in the changeset discussion. May be empty but never null
+     * @since 7704
+     */
+    public synchronized final List<ChangesetDiscussionComment> getDiscussion() {
+        if (discussion == null) {
+            return Collections.emptyList();
+        }
+        return new ArrayList<>(discussion);
+    }
+
+    /**
+     * Adds a comment to the changeset discussion.
+     * @param comment the comment to add. Ignored if null
+     * @since 7704
+     */
+    public synchronized final void addDiscussionComment(ChangesetDiscussionComment comment) {
+        if (comment == null) {
+            return;
+        }
+        if (discussion == null) {
+            discussion = new ArrayList<>();
+        }
+        discussion.add(comment);
+    }
 }
Index: trunk/src/org/openstreetmap/josm/data/osm/ChangesetDiscussionComment.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/ChangesetDiscussionComment.java	(revision 7704)
+++ trunk/src/org/openstreetmap/josm/data/osm/ChangesetDiscussionComment.java	(revision 7704)
@@ -0,0 +1,65 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.data.osm;
+
+import java.util.Date;
+
+/**
+ * A comment in a public changeset discussion.
+ * @since 7704
+ */
+public class ChangesetDiscussionComment {
+
+    /** date this comment was posted at */
+    private final Date date;
+    /** the user who posted the comment */
+    private final User user;
+    /** comment text */
+    private String text;
+
+    /**
+     * Constructs a new {@code ChangesetDiscussionComment}.
+     * @param date date this comment was posted at
+     * @param user the user who posted the comment
+     */
+    public ChangesetDiscussionComment(Date date, User user) {
+        this.date = date;
+        this.user = user;
+    }
+
+    /**
+     * Replies comment text.
+     * @return comment text
+     */
+    public final String getText() {
+        return text;
+    }
+
+    /**
+     * Sets comment text.
+     * @param text comment text
+     */
+    public final void setText(String text) {
+        this.text = text;
+    }
+
+    /**
+     * Replies date this comment was posted at.
+     * @return date this comment was posted at
+     */
+    public final Date getDate() {
+        return date;
+    }
+
+    /**
+     * Replies the user who posted the comment.
+     * @return the user who posted the comment
+     */
+    public final User getUser() {
+        return user;
+    }
+
+    @Override
+    public String toString() {
+        return "ChangesetDiscussionComment [date=" + date + ", user=" + user + ", text='" + text + "']";
+    }
+}
Index: trunk/src/org/openstreetmap/josm/gui/dialogs/changeset/ChangesetCacheManager.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/dialogs/changeset/ChangesetCacheManager.java	(revision 7702)
+++ trunk/src/org/openstreetmap/josm/gui/dialogs/changeset/ChangesetCacheManager.java	(revision 7704)
@@ -181,4 +181,9 @@
         model.addPropertyChangeListener(pnlChangesetContent);
 
+        // -- add the panel for the changeset discussion
+        ChangesetDiscussionPanel pnlChangesetDiscussion = new ChangesetDiscussionPanel();
+        tp.add(pnlChangesetDiscussion);
+        model.addPropertyChangeListener(pnlChangesetDiscussion);
+
         tp.setTitleAt(0, tr("Properties"));
         tp.setToolTipTextAt(0, tr("Display the basic properties of the changeset"));
@@ -187,4 +192,6 @@
         tp.setTitleAt(2, tr("Content"));
         tp.setToolTipTextAt(2, tr("Display the objects created, updated, and deleted by the changeset"));
+        tp.setTitleAt(3, tr("Discussion"));
+        tp.setToolTipTextAt(3, tr("Display the public discussion around this changeset"));
 
         pnl.add(tp, BorderLayout.CENTER);
Index: trunk/src/org/openstreetmap/josm/gui/dialogs/changeset/ChangesetContentDownloadTask.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/dialogs/changeset/ChangesetContentDownloadTask.java	(revision 7702)
+++ trunk/src/org/openstreetmap/josm/gui/dialogs/changeset/ChangesetContentDownloadTask.java	(revision 7704)
@@ -135,5 +135,5 @@
             reader = new OsmServerChangesetReader();
         }
-        Changeset cs = reader.readChangeset(changesetId, getProgressMonitor().createSubTaskMonitor(0, false));
+        Changeset cs = reader.readChangeset(changesetId, false, getProgressMonitor().createSubTaskMonitor(0, false));
         synchronized(this) {
             reader = null;
Index: trunk/src/org/openstreetmap/josm/gui/dialogs/changeset/ChangesetContentPanel.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/dialogs/changeset/ChangesetContentPanel.java	(revision 7702)
+++ trunk/src/org/openstreetmap/josm/gui/dialogs/changeset/ChangesetContentPanel.java	(revision 7704)
@@ -53,5 +53,5 @@
 
 /**
- * The panel which displays the content of a changeset in a scollable table.
+ * The panel which displays the content of a changeset in a scrollable table.
  *
  * It listens to property change events for {@link ChangesetCacheManagerModel#CHANGESET_IN_DETAIL_VIEW_PROP}
Index: trunk/src/org/openstreetmap/josm/gui/dialogs/changeset/ChangesetDiscussionPanel.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/dialogs/changeset/ChangesetDiscussionPanel.java	(revision 7704)
+++ trunk/src/org/openstreetmap/josm/gui/dialogs/changeset/ChangesetDiscussionPanel.java	(revision 7704)
@@ -0,0 +1,118 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.dialogs.changeset;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.BorderLayout;
+import java.awt.FlowLayout;
+import java.awt.event.ActionEvent;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.util.Collections;
+
+import javax.swing.AbstractAction;
+import javax.swing.BorderFactory;
+import javax.swing.JPanel;
+import javax.swing.JToolBar;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.osm.Changeset;
+import org.openstreetmap.josm.io.OnlineResource;
+
+/**
+ * The panel which displays the public discussion around a changeset in a scrollable table.
+ *
+ * It listens to property change events for {@link ChangesetCacheManagerModel#CHANGESET_IN_DETAIL_VIEW_PROP}
+ * and updates its view accordingly.
+ *
+ * @since 7704
+ */
+public class ChangesetDiscussionPanel extends JPanel implements PropertyChangeListener {
+
+    private final UpdateChangesetDiscussionAction actUpdateChangesets = new UpdateChangesetDiscussionAction();
+
+    private Changeset current = null;
+
+    protected JPanel buildActionButtonPanel() {
+        JPanel pnl = new JPanel(new FlowLayout(FlowLayout.LEFT));
+
+        JToolBar tb = new JToolBar(JToolBar.VERTICAL);
+        tb.setFloatable(false);
+
+        // -- changeset discussion update
+        tb.add(actUpdateChangesets);
+        actUpdateChangesets.initProperties(current);
+
+        pnl.add(tb);
+        return pnl;
+    }
+
+    /**
+     * Updates the current changeset discussion from the OSM server
+     */
+    class UpdateChangesetDiscussionAction extends AbstractAction {
+        public UpdateChangesetDiscussionAction() {
+            putValue(NAME, tr("Update changeset discussion"));
+            putValue(SMALL_ICON, ChangesetCacheManager.UPDATE_CONTENT_ICON);
+            putValue(SHORT_DESCRIPTION, tr("Update the changeset discussion from the OSM server"));
+        }
+
+        @Override
+        public void actionPerformed(ActionEvent evt) {
+            if (current == null) return;
+            Main.worker.submit(
+                    new ChangesetHeaderDownloadTask(
+                            ChangesetDiscussionPanel.this,
+                            Collections.singleton(current.getId()),
+                            true /* include discussion */
+                    )
+            );
+        }
+
+        public void initProperties(Changeset cs) {
+            setEnabled(cs != null && !Main.isOffline(OnlineResource.OSM_API));
+        }
+    }
+
+    /**
+     * Constructs a new {@code ChangesetDiscussionPanel}.
+     */
+    public ChangesetDiscussionPanel() {
+        build();
+    }
+
+    protected void setCurrentChangeset(Changeset cs) {
+        current = cs;
+        if (cs == null) {
+            clearView();
+        } else {
+            updateView(cs);
+        }
+        actUpdateChangesets.initProperties(current);
+    }
+
+    protected final void build() {
+        setLayout(new BorderLayout());
+        setBorder(BorderFactory.createEmptyBorder(3,3,3,3));
+        //add(buildDetailViewPanel(), BorderLayout.CENTER);
+        add(buildActionButtonPanel(), BorderLayout.WEST);
+    }
+
+    protected void clearView() {
+        // TODO
+    }
+
+    protected void updateView(Changeset cs) {
+        // TODO
+    }
+
+    /* ---------------------------------------------------------------------------- */
+    /* interface PropertyChangeListener                                             */
+    /* ---------------------------------------------------------------------------- */
+    @Override
+    public void propertyChange(PropertyChangeEvent evt) {
+        if (! evt.getPropertyName().equals(ChangesetCacheManagerModel.CHANGESET_IN_DETAIL_VIEW_PROP))
+            return;
+        setCurrentChangeset((Changeset)evt.getNewValue());
+    }
+}
Index: trunk/src/org/openstreetmap/josm/gui/dialogs/changeset/ChangesetHeaderDownloadTask.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/dialogs/changeset/ChangesetHeaderDownloadTask.java	(revision 7702)
+++ trunk/src/org/openstreetmap/josm/gui/dialogs/changeset/ChangesetHeaderDownloadTask.java	(revision 7704)
@@ -84,4 +84,5 @@
     private Exception lastException;
     private Set<Changeset> downloadedChangesets;
+    private final boolean includeDiscussion;
 
     protected void init(Collection<Integer> ids) {
@@ -112,4 +113,5 @@
         super(tr("Download changesets"), false /* don't ignore exceptions */);
         init(ids);
+        this.includeDiscussion = false;
     }
 
@@ -125,6 +127,24 @@
      */
     public ChangesetHeaderDownloadTask(Component dialogParent, Collection<Integer> ids) throws IllegalArgumentException{
-        super(dialogParent,tr("Download changesets"), false /* don't ignore exceptions */);
+        this(dialogParent, ids, false);
+    }
+
+    /**
+     * Creates the download task for a collection of changeset ids, with possibility to download changeset discussion.
+     * Uses a {@link org.openstreetmap.josm.gui.PleaseWaitDialog} whose parent is the parent window of <code>dialogParent</code>.
+     *
+     * Null ids or or ids &lt;= 0 in the id collection are ignored.
+     *
+     * @param dialogParent the parent reference component for the {@link org.openstreetmap.josm.gui.PleaseWaitDialog}. Must not be null.
+     * @param ids the collection of ids. Empty collection assumed if null.
+     * @param includeDiscussion determines if discussion comments must be downloaded or not
+     * @throws IllegalArgumentException thrown if dialogParent is null
+     * @since 7704
+     */
+    public ChangesetHeaderDownloadTask(Component dialogParent, Collection<Integer> ids, boolean includeDiscussion)
+            throws IllegalArgumentException {
+        super(dialogParent, tr("Download changesets"), false /* don't ignore exceptions */);
         init(ids);
+        this.includeDiscussion = includeDiscussion;
     }
 
@@ -180,5 +200,6 @@
             }
             downloadedChangesets = new HashSet<>();
-            downloadedChangesets.addAll(reader.readChangesets(idsToDownload, getProgressMonitor().createSubTaskMonitor(0, false)));
+            downloadedChangesets.addAll(reader.readChangesets(idsToDownload, includeDiscussion,
+                    getProgressMonitor().createSubTaskMonitor(0, false)));
         } catch(OsmTransferException e) {
             if (canceled)
Index: trunk/src/org/openstreetmap/josm/io/OsmChangesetParser.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/OsmChangesetParser.java	(revision 7702)
+++ trunk/src/org/openstreetmap/josm/io/OsmChangesetParser.java	(revision 7704)
@@ -8,4 +8,5 @@
 import java.nio.charset.StandardCharsets;
 import java.text.MessageFormat;
+import java.util.Date;
 import java.util.LinkedList;
 import java.util.List;
@@ -16,4 +17,5 @@
 import org.openstreetmap.josm.data.coor.LatLon;
 import org.openstreetmap.josm.data.osm.Changeset;
+import org.openstreetmap.josm.data.osm.ChangesetDiscussionComment;
 import org.openstreetmap.josm.data.osm.User;
 import org.openstreetmap.josm.gui.progress.ProgressMonitor;
@@ -70,4 +72,10 @@
         private Changeset current = null;
 
+        /** The current comment */
+        private ChangesetDiscussionComment comment = null;
+
+        /** The current comment text */
+        private StringBuilder text = null;
+
         protected void parseChangesetAttributes(Changeset cs, Attributes atts) throws XmlParsingException {
             // -- id
@@ -78,8 +86,6 @@
             current.setId(parseNumericAttribute(value, 1));
 
-            // -- user
-            String user = atts.getValue("user");
-            String uid = atts.getValue("uid");
-            current.setUser(createUser(uid, user));
+            // -- user / uid
+            current.setUser(createUser(atts));
 
             // -- created_at
@@ -155,4 +161,15 @@
         }
 
+        private void parseCommentAttributes(Attributes atts) throws XmlParsingException {
+            // -- date
+            String value = atts.getValue("date");
+            Date date = null;
+            if (value != null) {
+                date = DateUtils.fromString(value);
+            }
+
+            comment = new ChangesetDiscussionComment(date, createUser(atts));
+        }
+
         private int parseNumericAttribute(String value, int minAllowed) throws XmlParsingException {
             int att = 0;
@@ -193,6 +210,21 @@
                 current.put(key, value);
                 break;
+            case "discussion":
+                break;
+            case "comment":
+                parseCommentAttributes(atts);
+                break;
+            case "text":
+                text = new StringBuilder();
+                break;
             default:
                 throwException(tr("Undefined element ''{0}'' found in input stream. Aborting.", qName));
+            }
+        }
+
+        @Override
+        public void characters(char[] ch, int start, int length) throws SAXException {
+            if (text != null) {
+                text.append(ch, start, length);
             }
         }
@@ -202,8 +234,17 @@
             if ("changeset".equals(qName)) {
                 changesets.add(current);
-            }
-        }
-
-        protected User createUser(String uid, String name) throws XmlParsingException {
+                current = null;
+            } else if ("comment".equals(qName)) {
+                current.addDiscussionComment(comment);
+                comment = null;
+            } else if ("text".equals(qName)) {
+                comment.setText(text.toString());
+                text = null;
+            }
+        }
+
+        protected User createUser(Attributes atts) throws XmlParsingException {
+            String name = atts.getValue("user");
+            String uid = atts.getValue("uid");
             if (uid == null) {
                 if (name == null)
Index: trunk/src/org/openstreetmap/josm/io/OsmServerChangesetReader.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/OsmServerChangesetReader.java	(revision 7702)
+++ trunk/src/org/openstreetmap/josm/io/OsmServerChangesetReader.java	(revision 7704)
@@ -29,8 +29,7 @@
 
     /**
-     * constructor
-     *
-     */
-    public OsmServerChangesetReader(){
+     * Constructs a new {@code OsmServerChangesetReader}.
+     */
+    public OsmServerChangesetReader() {
         setDoAuthenticate(false);
     }
@@ -38,9 +37,18 @@
     /**
      * don't use - not implemented!
-     *
      */
     @Override
     public DataSet parseOsm(ProgressMonitor progressMonitor) throws OsmTransferException {
         return null;
+    }
+
+    protected final InputStream getChangesetInputStream(long id, boolean includeDiscussion, ProgressMonitor monitor)
+            throws OsmTransferException {
+        StringBuilder sb = new StringBuilder();
+        sb.append("changeset/").append(id);
+        if (includeDiscussion) {
+            sb.append("?include_discussion=true");
+        }
+        return getInputStream(sb.toString(), monitor.createSubTaskMonitor(1, true));
     }
 
@@ -82,13 +90,15 @@
 
     /**
-     * Reads the changeset with id <code>id</code> from the server
+     * Reads the changeset with id <code>id</code> from the server.
      *
-     * @param id  the changeset id. id &gt; 0 required.
+     * @param id the changeset id. id &gt; 0 required.
+     * @param includeDiscussion determines if discussion comments must be downloaded or not
      * @param monitor the progress monitor. Set to {@link NullProgressMonitor#INSTANCE} if null
      * @return the changeset read
      * @throws OsmTransferException thrown if something goes wrong
      * @throws IllegalArgumentException if id &lt;= 0
-     */
-    public Changeset readChangeset(long id, ProgressMonitor monitor) throws OsmTransferException {
+     * @since 7704
+     */
+    public Changeset readChangeset(long id, boolean includeDiscussion, ProgressMonitor monitor) throws OsmTransferException {
         if (id <= 0)
             throw new IllegalArgumentException(MessageFormat.format("Parameter ''{0}'' > 0 expected. Got ''{1}''.", "id", id));
@@ -99,7 +109,5 @@
         try {
             monitor.beginTask(tr("Reading changeset {0} ...",id));
-            StringBuilder sb = new StringBuilder();
-            sb.append("changeset/").append(id);
-            try (InputStream in = getInputStream(sb.toString(), monitor.createSubTaskMonitor(1, true))) {
+            try (InputStream in = getChangesetInputStream(id, includeDiscussion, monitor)) {
                 if (in == null)
                     return null;
@@ -123,13 +131,15 @@
 
     /**
-     * Reads the changeset with id <code>id</code> from the server
+     * Reads the changesets with id <code>ids</code> from the server.
      *
-     * @param ids  the list of ids. Ignored if null. Only load changesets for ids &gt; 0.
+     * @param ids the list of ids. Ignored if null. Only load changesets for ids &gt; 0.
+     * @param includeDiscussion determines if discussion comments must be downloaded or not
      * @param monitor the progress monitor. Set to {@link NullProgressMonitor#INSTANCE} if null
      * @return the changeset read
      * @throws OsmTransferException thrown if something goes wrong
      * @throws IllegalArgumentException if id &lt;= 0
-     */
-    public List<Changeset> readChangesets(Collection<Integer> ids, ProgressMonitor monitor) throws OsmTransferException {
+     * @since 7704
+     */
+    public List<Changeset> readChangesets(Collection<Integer> ids, boolean includeDiscussion, ProgressMonitor monitor) throws OsmTransferException {
         if (ids == null)
             return Collections.emptyList();
@@ -147,7 +157,5 @@
                 }
                 i++;
-                StringBuilder sb = new StringBuilder();
-                sb.append("changeset/").append(id);
-                try (InputStream in = getInputStream(sb.toString(), monitor.createSubTaskMonitor(1, true))) {
+                try (InputStream in = getChangesetInputStream(id, includeDiscussion, monitor)) {
                     if (in == null)
                         return null;
