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