001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.gui.dialogs.changeset; 003 004import static org.openstreetmap.josm.tools.I18n.tr; 005 006import java.awt.BorderLayout; 007import java.awt.Component; 008import java.awt.FlowLayout; 009import java.awt.Rectangle; 010import java.awt.event.ActionEvent; 011import java.beans.PropertyChangeEvent; 012import java.beans.PropertyChangeListener; 013import java.util.Collections; 014 015import javax.swing.AbstractAction; 016import javax.swing.BorderFactory; 017import javax.swing.JPanel; 018import javax.swing.JScrollPane; 019import javax.swing.JTable; 020import javax.swing.JToolBar; 021 022import org.openstreetmap.josm.Main; 023import org.openstreetmap.josm.actions.downloadtasks.ChangesetHeaderDownloadTask; 024import org.openstreetmap.josm.actions.downloadtasks.PostDownloadHandler; 025import org.openstreetmap.josm.data.osm.Changeset; 026import org.openstreetmap.josm.io.OnlineResource; 027import org.openstreetmap.josm.tools.ImageProvider; 028 029/** 030 * The panel which displays the public discussion around a changeset in a scrollable table. 031 * 032 * It listens to property change events for {@link ChangesetCacheManagerModel#CHANGESET_IN_DETAIL_VIEW_PROP} 033 * and updates its view accordingly. 034 * 035 * @since 7704 036 */ 037public class ChangesetDiscussionPanel extends JPanel implements PropertyChangeListener { 038 039 private final UpdateChangesetDiscussionAction actUpdateChangesets = new UpdateChangesetDiscussionAction(); 040 041 private final ChangesetDiscussionTableModel model = new ChangesetDiscussionTableModel(); 042 043 private JTable table; 044 045 private transient Changeset current; 046 047 protected JPanel buildActionButtonPanel() { 048 JPanel pnl = new JPanel(new FlowLayout(FlowLayout.LEFT)); 049 050 JToolBar tb = new JToolBar(JToolBar.VERTICAL); 051 tb.setFloatable(false); 052 053 // -- changeset discussion update 054 tb.add(actUpdateChangesets); 055 actUpdateChangesets.initProperties(current); 056 057 pnl.add(tb); 058 return pnl; 059 } 060 061 /** 062 * Updates the current changeset discussion from the OSM server 063 */ 064 class UpdateChangesetDiscussionAction extends AbstractAction { 065 UpdateChangesetDiscussionAction() { 066 putValue(NAME, tr("Update changeset discussion")); 067 new ImageProvider("dialogs/changeset", "updatechangesetcontent").getResource().attachImageIcon(this); 068 putValue(SHORT_DESCRIPTION, tr("Update the changeset discussion from the OSM server")); 069 } 070 071 @Override 072 public void actionPerformed(ActionEvent evt) { 073 if (current == null) 074 return; 075 ChangesetHeaderDownloadTask task = new ChangesetHeaderDownloadTask( 076 ChangesetDiscussionPanel.this, 077 Collections.singleton(current.getId()), 078 true /* include discussion */ 079 ); 080 Main.worker.submit(new PostDownloadHandler(task, task.download())); 081 } 082 083 public void initProperties(Changeset cs) { 084 setEnabled(cs != null && !Main.isOffline(OnlineResource.OSM_API)); 085 } 086 } 087 088 /** 089 * Constructs a new {@code ChangesetDiscussionPanel}. 090 */ 091 public ChangesetDiscussionPanel() { 092 build(); 093 } 094 095 protected void setCurrentChangeset(Changeset cs) { 096 current = cs; 097 if (cs == null) { 098 clearView(); 099 } else { 100 updateView(cs); 101 } 102 actUpdateChangesets.initProperties(current); 103 if (cs != null && cs.getDiscussion().size() < cs.getCommentsCount()) { 104 actUpdateChangesets.actionPerformed(null); 105 } 106 } 107 108 protected final void build() { 109 setLayout(new BorderLayout()); 110 setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3)); 111 add(buildActionButtonPanel(), BorderLayout.WEST); 112 add(buildDiscussionPanel(), BorderLayout.CENTER); 113 } 114 115 private Component buildDiscussionPanel() { 116 JPanel pnl = new JPanel(new BorderLayout()); 117 table = new JTable(model, new ChangesetDiscussionTableColumnModel()); 118 table.getColumnModel().getColumn(2).addPropertyChangeListener(new PropertyChangeListener() { 119 @Override 120 public void propertyChange(PropertyChangeEvent evt) { 121 if ("width".equals(evt.getPropertyName())) { 122 updateRowHeights(); 123 } 124 } 125 }); 126 pnl.add(new JScrollPane(table), BorderLayout.CENTER); 127 return pnl; 128 } 129 130 protected void clearView() { 131 model.populate(null); 132 } 133 134 protected void updateView(Changeset cs) { 135 model.populate(cs.getDiscussion()); 136 updateRowHeights(); 137 } 138 139 protected void updateRowHeights() { 140 int intercellWidth = table.getIntercellSpacing().width; 141 int colWidth = table.getColumnModel().getColumn(2).getWidth(); 142 // Update row heights 143 for (int row = 0; row < table.getRowCount(); row++) { 144 int rowHeight = table.getRowHeight(); 145 146 Component comp = table.prepareRenderer(table.getCellRenderer(row, 2), row, 2); 147 // constrain width of component 148 comp.setBounds(new Rectangle(0, 0, colWidth - intercellWidth, Integer.MAX_VALUE)); 149 rowHeight = Math.max(rowHeight, comp.getPreferredSize().height); 150 151 table.setRowHeight(row, rowHeight); 152 } 153 } 154 155 /* ---------------------------------------------------------------------------- */ 156 /* interface PropertyChangeListener */ 157 /* ---------------------------------------------------------------------------- */ 158 @Override 159 public void propertyChange(PropertyChangeEvent evt) { 160 if (!evt.getPropertyName().equals(ChangesetCacheManagerModel.CHANGESET_IN_DETAIL_VIEW_PROP)) 161 return; 162 setCurrentChangeset((Changeset) evt.getNewValue()); 163 } 164}