001 // License: GPL. Copyright 2007 by Immanuel Scholz and others 002 package org.openstreetmap.josm.gui.dialogs; 003 004 import static org.openstreetmap.josm.tools.I18n.tr; 005 006 import java.awt.Component; 007 import java.awt.event.ActionEvent; 008 import java.awt.event.KeyEvent; 009 import java.awt.event.MouseAdapter; 010 import java.awt.event.MouseEvent; 011 import java.util.ArrayList; 012 import java.util.Arrays; 013 import java.util.Collection; 014 import java.util.Collections; 015 import java.util.List; 016 017 import javax.swing.AbstractAction; 018 import javax.swing.Action; 019 import javax.swing.DefaultListSelectionModel; 020 import javax.swing.JComponent; 021 import javax.swing.JLabel; 022 import javax.swing.JTable; 023 import javax.swing.ListSelectionModel; 024 import javax.swing.event.ListSelectionEvent; 025 import javax.swing.event.ListSelectionListener; 026 import javax.swing.table.DefaultTableCellRenderer; 027 import javax.swing.table.DefaultTableColumnModel; 028 import javax.swing.table.DefaultTableModel; 029 import javax.swing.table.TableCellRenderer; 030 import javax.swing.table.TableColumn; 031 032 import org.openstreetmap.josm.Main; 033 import org.openstreetmap.josm.data.SelectionChangedListener; 034 import org.openstreetmap.josm.data.osm.DataSet; 035 import org.openstreetmap.josm.data.osm.OsmPrimitive; 036 import org.openstreetmap.josm.data.osm.PrimitiveId; 037 import org.openstreetmap.josm.data.osm.history.HistoryDataSet; 038 import org.openstreetmap.josm.data.osm.history.HistoryDataSetListener; 039 import org.openstreetmap.josm.gui.OsmPrimitivRenderer; 040 import org.openstreetmap.josm.gui.SideButton; 041 import org.openstreetmap.josm.gui.help.HelpUtil; 042 import org.openstreetmap.josm.gui.history.HistoryBrowserDialogManager; 043 import org.openstreetmap.josm.gui.history.HistoryLoadTask; 044 import org.openstreetmap.josm.tools.ImageProvider; 045 import org.openstreetmap.josm.tools.InputMapUtils; 046 import org.openstreetmap.josm.tools.Shortcut; 047 048 /** 049 * HistoryDialog displays a list of the currently selected primitives and provides 050 * two actions for (1) (re)loading the history of the selected primitives and (2) 051 * for launching a history browser for each selected primitive. 052 * 053 */ 054 public class HistoryDialog extends ToggleDialog implements HistoryDataSetListener { 055 056 /** the table model */ 057 protected HistoryItemTableModel model; 058 /** the table with the history items */ 059 protected JTable historyTable; 060 061 protected ShowHistoryAction showHistoryAction; 062 protected ReloadAction reloadAction; 063 064 public HistoryDialog() { 065 super(tr("History"), "history", tr("Display the history of all selected items."), 066 Shortcut.registerShortcut("subwindow:history", tr("Toggle: {0}", tr("History")), KeyEvent.VK_H, 067 Shortcut.ALT_SHIFT), 150); 068 build(); 069 HelpUtil.setHelpContext(this, HelpUtil.ht("/Dialog/History")); 070 } 071 072 /** 073 * builds the GUI 074 */ 075 protected void build() { 076 DefaultListSelectionModel selectionModel = new DefaultListSelectionModel(); 077 historyTable = new JTable( 078 model = new HistoryItemTableModel(selectionModel), 079 new HistoryTableColumnModel(), 080 selectionModel 081 ); 082 historyTable.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); 083 final TableCellRenderer oldRenderer = historyTable.getTableHeader().getDefaultRenderer(); 084 historyTable.getTableHeader().setDefaultRenderer(new DefaultTableCellRenderer(){ 085 @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { 086 JComponent c = (JComponent)oldRenderer.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); 087 if (!"".equals(value)) 088 return c; 089 JLabel l = new JLabel(ImageProvider.get("misc","showhide")); 090 l.setForeground(c.getForeground()); 091 l.setBackground(c.getBackground()); 092 l.setFont(c.getFont()); 093 l.setBorder(c.getBorder()); 094 l.setOpaque(true); 095 return l; 096 } 097 }); 098 historyTable.addMouseListener(new ShowHistoryMouseAdapter()); 099 historyTable.setTableHeader(null); 100 101 createLayout(historyTable, true, Arrays.asList(new SideButton[] { 102 new SideButton(reloadAction = new ReloadAction()), 103 new SideButton(showHistoryAction = new ShowHistoryAction()) 104 })); 105 106 // wire actions 107 // 108 historyTable.getSelectionModel().addListSelectionListener(showHistoryAction); 109 historyTable.getSelectionModel().addListSelectionListener(reloadAction); 110 111 // Show history dialog on Enter/Spacebar 112 InputMapUtils.addEnterAction(historyTable, showHistoryAction); 113 InputMapUtils.addSpacebarAction(historyTable, showHistoryAction); 114 } 115 116 @Override 117 public void showNotify() { 118 HistoryDataSet.getInstance().addHistoryDataSetListener(this); 119 DataSet.addSelectionListener(model); 120 if (Main.main.getCurrentDataSet() == null) { 121 model.selectionChanged(null); 122 } else { 123 model.selectionChanged(Main.main.getCurrentDataSet().getAllSelected()); 124 } 125 } 126 127 @Override 128 public void hideNotify() { 129 HistoryDataSet.getInstance().removeHistoryDataSetListener(this); 130 DataSet.removeSelectionListener(model); 131 } 132 133 /* ----------------------------------------------------------------------------- */ 134 /* interface HistoryDataSetListener */ 135 /* ----------------------------------------------------------------------------- */ 136 public void historyUpdated(HistoryDataSet source, PrimitiveId primitiveId) { 137 model.refresh(); 138 } 139 140 public void historyDataSetCleared(HistoryDataSet source) { 141 model.refresh(); 142 } 143 144 /** 145 * The table model with the history items 146 * 147 */ 148 static class HistoryItemTableModel extends DefaultTableModel implements SelectionChangedListener{ 149 private ArrayList<OsmPrimitive> data; 150 private DefaultListSelectionModel selectionModel; 151 152 public HistoryItemTableModel(DefaultListSelectionModel selectionModel) { 153 data = new ArrayList<OsmPrimitive>(); 154 this.selectionModel = selectionModel; 155 } 156 157 @Override 158 public int getRowCount() { 159 if (data == null) 160 return 0; 161 return data.size(); 162 } 163 164 @Override 165 public Object getValueAt(int row, int column) { 166 return data.get(row); 167 } 168 169 @Override 170 public boolean isCellEditable(int row, int column) { 171 return false; 172 } 173 174 protected List<OsmPrimitive> getSelectedPrimitives() { 175 ArrayList<OsmPrimitive> ret = new ArrayList<OsmPrimitive>(); 176 for (int i=0; i< data.size(); i++) { 177 if (selectionModel.isSelectedIndex(i)) { 178 ret.add(data.get(i)); 179 } 180 } 181 return ret; 182 } 183 184 protected void selectPrimitives(Collection<OsmPrimitive> primitives) { 185 for (OsmPrimitive p: primitives) { 186 int idx = data.indexOf(p); 187 if (idx < 0) { 188 continue; 189 } 190 selectionModel.addSelectionInterval(idx, idx); 191 } 192 } 193 194 public void refresh() { 195 List<OsmPrimitive> selectedPrimitives = getSelectedPrimitives(); 196 data.clear(); 197 if (Main.main.getCurrentDataSet() == null) 198 return; 199 for (OsmPrimitive primitive: Main.main.getCurrentDataSet().getAllSelected()) { 200 if (primitive.isNew()) { 201 continue; 202 } 203 data.add(primitive); 204 } 205 fireTableDataChanged(); 206 selectPrimitives(selectedPrimitives); 207 } 208 209 public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) { 210 data.clear(); 211 selectionModel.clearSelection(); 212 if (newSelection != null && !newSelection.isEmpty()) { 213 for (OsmPrimitive primitive: newSelection) { 214 if (primitive.isNew()) { 215 continue; 216 } 217 data.add(primitive); 218 } 219 } 220 fireTableDataChanged(); 221 selectionModel.addSelectionInterval(0, data.size()-1); 222 } 223 224 public List<OsmPrimitive> getPrimitives(int [] rows) { 225 if (rows == null || rows.length == 0) return Collections.emptyList(); 226 ArrayList<OsmPrimitive> ret = new ArrayList<OsmPrimitive>(rows.length); 227 for (int row: rows) { 228 ret.add(data.get(row)); 229 } 230 return ret; 231 } 232 233 public OsmPrimitive getPrimitive(int row) { 234 return data.get(row); 235 } 236 } 237 238 /** 239 * The column model 240 */ 241 static class HistoryTableColumnModel extends DefaultTableColumnModel { 242 protected void createColumns() { 243 TableColumn col = null; 244 OsmPrimitivRenderer renderer = new OsmPrimitivRenderer(); 245 // column 0 - History item 246 col = new TableColumn(0); 247 col.setHeaderValue(tr("Object with history")); 248 col.setCellRenderer(renderer); 249 addColumn(col); 250 } 251 252 public HistoryTableColumnModel() { 253 createColumns(); 254 } 255 } 256 257 /** 258 * The action for reloading history information of the currently selected primitives. 259 * 260 */ 261 class ReloadAction extends AbstractAction implements ListSelectionListener { 262 263 public ReloadAction() { 264 putValue(Action.SMALL_ICON, ImageProvider.get("dialogs","refresh")); 265 putValue(Action.NAME, tr("Reload")); 266 putValue(Action.SHORT_DESCRIPTION, tr("Reload all currently selected objects and refresh the list.")); 267 updateEnabledState(); 268 } 269 270 public void actionPerformed(ActionEvent e) { 271 int [] rows = historyTable.getSelectedRows(); 272 if (rows == null || rows.length == 0) return; 273 274 List<OsmPrimitive> selectedItems = model.getPrimitives(rows); 275 HistoryLoadTask task = new HistoryLoadTask(); 276 task.add(selectedItems); 277 Main.worker.execute(task); 278 } 279 280 protected void updateEnabledState() { 281 setEnabled(historyTable.getSelectedRowCount() > 0); 282 } 283 284 public void valueChanged(ListSelectionEvent e) { 285 updateEnabledState(); 286 } 287 } 288 289 class ShowHistoryMouseAdapter extends MouseAdapter { 290 @Override 291 public void mouseClicked(MouseEvent e) { 292 if (e.getClickCount() == 2 && e.getButton() == MouseEvent.BUTTON1) { 293 int row = historyTable.rowAtPoint(e.getPoint()); 294 HistoryBrowserDialogManager.getInstance().showHistory(Collections.singletonList(model.getPrimitive(row))); 295 } 296 } 297 } 298 299 /** 300 * The action for showing history information of the current history item. 301 */ 302 class ShowHistoryAction extends AbstractAction implements ListSelectionListener { 303 public ShowHistoryAction() { 304 putValue(Action.SMALL_ICON, ImageProvider.get("dialogs","history")); 305 putValue(Action.NAME, tr("Show")); 306 putValue(Action.SHORT_DESCRIPTION, tr("Display the history of the selected objects.")); 307 updateEnabledState(); 308 } 309 310 public void actionPerformed(ActionEvent e) { 311 int [] rows = historyTable.getSelectedRows(); 312 if (rows == null || rows.length == 0) return; 313 HistoryBrowserDialogManager.getInstance().showHistory(model.getPrimitives(rows)); 314 } 315 316 protected void updateEnabledState() { 317 setEnabled(historyTable.getSelectedRowCount() > 0); 318 } 319 320 public void valueChanged(ListSelectionEvent e) { 321 updateEnabledState(); 322 } 323 } 324 }