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