Changeset 1709 in josm for trunk/src/org
- Timestamp:
- 2009-06-28T11:37:21+02:00 (15 years ago)
- Location:
- trunk/src/org/openstreetmap/josm
- Files:
-
- 20 added
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/org/openstreetmap/josm/data/osm/history/HistoryDataSet.java
r1670 r1709 9 9 10 10 public class HistoryDataSet { 11 12 private static HistoryDataSet historyDataSet; 13 14 public static HistoryDataSet getInstance() { 15 if (historyDataSet == null) { 16 historyDataSet = new HistoryDataSet(); 17 } 18 return historyDataSet; 19 } 11 20 12 21 private HashMap<Long, ArrayList<HistoryOsmPrimitive>> data; … … 44 53 ArrayList<HistoryOsmPrimitive> versions = data.get(id); 45 54 if (versions == null) 46 throw new NoSuchElementException(tr("Didn't find an historized primitive with id {0} in this dataset", id));55 return null; 47 56 return new History(id, versions); 48 57 } 58 59 /** 60 * merges the histories from the {@see HistoryDataSet} other in this history data set 61 * 62 * @param other the other history data set. Ignored if null. 63 */ 64 public void mergeInto(HistoryDataSet other) { 65 if (other == null) 66 return; 67 for (Long id : other.data.keySet()) { 68 if (!this.data.keySet().contains(id)) { 69 this.data.put(id, other.data.get(id)); 70 } 71 } 72 } 49 73 } -
trunk/src/org/openstreetmap/josm/data/osm/history/HistoryOsmPrimitive.java
r1670 r1709 2 2 package org.openstreetmap.josm.data.osm.history; 3 3 4 import java.util.Collections; 4 5 import java.util.Date; 5 6 import java.util.HashMap; 7 import java.util.Map; 6 8 7 9 import org.openstreetmap.josm.data.osm.OsmPrimitiveType; … … 116 118 } 117 119 120 public Map<String,String> getTags() { 121 return Collections.unmodifiableMap(tags); 122 } 123 118 124 @Override 119 125 public int hashCode() { -
trunk/src/org/openstreetmap/josm/gui/dialogs/HistoryDialog.java
r1499 r1709 3 3 4 4 import static org.openstreetmap.josm.tools.I18n.tr; 5 import static org.openstreetmap.josm.tools.I18n.marktr;6 5 7 6 import java.awt.BorderLayout; 7 import java.awt.Color; 8 8 import java.awt.Component; 9 import java.awt.GridBagLayout;10 9 import java.awt.GridLayout; 11 10 import java.awt.event.ActionEvent; 12 import java.awt.event.ActionListener;13 11 import java.awt.event.KeyEvent; 14 import java.util.Calendar; 12 import java.awt.event.MouseAdapter; 13 import java.awt.event.MouseEvent; 14 import java.io.IOException; 15 import java.util.ArrayList; 15 16 import java.util.Collection; 16 import java.util.Date;17 17 import java.util.HashMap; 18 import java.util.List; 19 import java.util.Map; 20 import java.util.SortedSet; 21 import java.util.TreeSet; 22 18 import java.util.Iterator; 19 20 import javax.swing.AbstractAction; 21 import javax.swing.Action; 22 import javax.swing.ImageIcon; 23 import javax.swing.JButton; 23 24 import javax.swing.JComponent; 24 25 import javax.swing.JLabel; … … 27 28 import javax.swing.JScrollPane; 28 29 import javax.swing.JTable; 30 import javax.swing.ListSelectionModel; 31 import javax.swing.SwingUtilities; 32 import javax.swing.event.ListSelectionEvent; 33 import javax.swing.event.ListSelectionListener; 29 34 import javax.swing.table.DefaultTableCellRenderer; 35 import javax.swing.table.DefaultTableColumnModel; 30 36 import javax.swing.table.DefaultTableModel; 31 37 import javax.swing.table.TableCellRenderer; 38 import javax.swing.table.TableColumn; 32 39 33 40 import org.openstreetmap.josm.Main; … … 35 42 import org.openstreetmap.josm.data.osm.DataSet; 36 43 import org.openstreetmap.josm.data.osm.OsmPrimitive; 37 import org.openstreetmap.josm.gui.SideButton; 38 import org.openstreetmap.josm.tools.DateUtils; 39 import org.openstreetmap.josm.tools.GBC; 44 import org.openstreetmap.josm.data.osm.OsmPrimitiveType; 45 import org.openstreetmap.josm.data.osm.history.History; 46 import org.openstreetmap.josm.data.osm.history.HistoryDataSet; 47 import org.openstreetmap.josm.gui.PleaseWaitRunnable; 48 import org.openstreetmap.josm.gui.history.HistoryBrowserDialog; 49 import org.openstreetmap.josm.io.OsmApi; 50 import org.openstreetmap.josm.io.OsmServerHistoryReader; 51 import org.openstreetmap.josm.io.OsmTransferException; 40 52 import org.openstreetmap.josm.tools.ImageProvider; 41 53 import org.openstreetmap.josm.tools.Shortcut; 54 import org.xml.sax.SAXException; 42 55 43 56 /** … … 53 66 * @author imi 54 67 */ 55 public class HistoryDialog extends ToggleDialog implements SelectionChangedListener { 56 57 public static final Date unifyDate(Date d) { 58 Calendar c = Calendar.getInstance(); 59 c.setTime(d); 60 c.set(Calendar.MINUTE, 0); 61 c.set(Calendar.SECOND, 0); 62 return c.getTime(); 63 } 64 65 private static class HistoryItem implements Comparable<HistoryItem> { 66 OsmPrimitive osm; 67 boolean visible; 68 69 public int compareTo(HistoryItem o) { 70 return unifyDate(osm.getTimestamp()).compareTo(unifyDate(o.osm.getTimestamp())); 71 } 72 } 73 74 private final DefaultTableModel data = new DefaultTableModel(){ 75 @Override public boolean isCellEditable(int row, int column) { 76 return false; 77 } 78 }; 79 80 /** 81 * Main table. 3 columns: 82 * Object | Date | visible (icon, no text) 83 */ 84 private JTable history = new JTable(data); 85 private JScrollPane historyPane = new JScrollPane(history); 86 87 private Map<OsmPrimitive, List<HistoryItem>> cache = new HashMap<OsmPrimitive, List<HistoryItem>>(); 88 private JLabel notLoaded = new JLabel("<html><i>"+tr("Click Reload to refresh list")+"</i></html>"); 89 90 public HistoryDialog() { 91 super(tr("History"), "history", tr("Display the history of all selected items."), 92 Shortcut.registerShortcut("subwindow:history", tr("Toggle: {0}", tr("History")), KeyEvent.VK_H, 93 Shortcut.GROUP_LAYER, Shortcut.SHIFT_DEFAULT), 150); 94 historyPane.setVisible(false); 95 notLoaded.setVisible(true); 96 notLoaded.setHorizontalAlignment(JLabel.CENTER); 97 98 history.setDefaultRenderer(Object.class, new DefaultTableCellRenderer(){ 99 @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { 100 return super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); 101 } 102 }); 103 data.setColumnIdentifiers(new Object[]{tr("Object"),tr("Date"),""}); 104 history.getColumnModel().getColumn(0).setPreferredWidth(200); 105 history.getColumnModel().getColumn(1).setPreferredWidth(200); 106 history.getColumnModel().getColumn(2).setPreferredWidth(20); 107 final TableCellRenderer oldRenderer = history.getTableHeader().getDefaultRenderer(); 108 history.getTableHeader().setDefaultRenderer(new DefaultTableCellRenderer(){ 68 public class HistoryDialog extends ToggleDialog { 69 70 /** the registry of history browser dialogs which are currently displaying */ 71 static private HashMap<Long, HistoryBrowserDialog> historyBrowserDialogs; 72 73 /** 74 * registers a {@see HistoryBrowserDialog} 75 * @param id the id of the primitive dialog shows the history for 76 * @param dialog the dialog 77 */ 78 public static void registerHistoryBrowserDialog(long id, HistoryBrowserDialog dialog) { 79 if (historyBrowserDialogs == null) { 80 historyBrowserDialogs = new HashMap<Long, HistoryBrowserDialog>(); 81 } 82 historyBrowserDialogs.put(id, dialog); 83 } 84 85 /** 86 * unregisters a {@see HistoryBrowserDialog} 87 * @param id the id of the primitive whose history dialog is to be unregistered 88 * 89 */ 90 public static void unregisterHistoryBrowserDialog(long id) { 91 if (historyBrowserDialogs == null) 92 return; 93 historyBrowserDialogs.remove(id); 94 } 95 96 /** 97 * replies the history dialog for the primitive with id <code>id</code>; null, if 98 * no such {@see HistoryBrowserDialog} is currently showing 99 * 100 * @param id the id of the primitive 101 * @return the dialog; null, if no such dialog is showing 102 */ 103 public static HistoryBrowserDialog getHistoryBrowserDialog(long id) { 104 if (historyBrowserDialogs == null) 105 return null; 106 return historyBrowserDialogs.get(id); 107 } 108 109 110 /** the table model */ 111 protected HistoryItemDataModel model; 112 /** the table with the history items */ 113 protected JTable historyTable; 114 115 protected ShowHistoryAction showHistoryAction; 116 protected ReloadAction reloadAction; 117 118 /** 119 * builds the row with the command buttons 120 * 121 * @return the rows with the command buttons 122 */ 123 protected JPanel buildButtonRow() { 124 JPanel buttons = new JPanel(new GridLayout(1,2)); 125 126 JButton btn = new JButton(reloadAction = new ReloadAction()); 127 btn.setName("btn.reload"); 128 buttons.add(btn); 129 130 btn = new JButton(showHistoryAction = new ShowHistoryAction()); 131 btn.setName("btn.showhistory"); 132 buttons.add(btn); 133 134 return buttons; 135 } 136 137 /** 138 * builds the GUI 139 */ 140 protected void build() { 141 model = new HistoryItemDataModel(); 142 //setLayout(new BorderLayout()); 143 historyTable = new JTable( 144 model, 145 new HistoryTableColumnModel() 146 ); 147 historyTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); 148 historyTable.setName("table.historyitems"); 149 final TableCellRenderer oldRenderer = historyTable.getTableHeader().getDefaultRenderer(); 150 historyTable.getTableHeader().setDefaultRenderer(new DefaultTableCellRenderer(){ 109 151 @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { 110 152 JComponent c = (JComponent)oldRenderer.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); … … 120 162 } 121 163 }); 122 123 JPanel centerPanel = new JPanel(new GridBagLayout()); 124 centerPanel.add(notLoaded, GBC.eol().fill(GBC.BOTH)); 125 centerPanel.add(historyPane, GBC.eol().fill(GBC.BOTH)); 126 add(centerPanel, BorderLayout.CENTER); 127 128 JPanel buttons = new JPanel(new GridLayout(1,2)); 129 buttons.add(new SideButton(marktr("Reload"), "refresh", "History", tr("Reload all currently selected objects and refresh the list."), 130 new ActionListener(){ 131 public void actionPerformed(ActionEvent e) { 132 reload(); 164 historyTable.addMouseListener( 165 new MouseAdapter() { 166 @Override 167 public void mouseClicked(MouseEvent e) { 168 if (e.getClickCount() == 2) { 169 int row = historyTable.rowAtPoint(e.getPoint()); 170 History h = model.get(row); 171 showHistory(h); 172 } 173 } 174 } 175 ); 176 177 JScrollPane pane = new JScrollPane(historyTable); 178 pane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); 179 pane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED); 180 historyTable.setTableHeader(null); 181 pane.setColumnHeaderView(null); 182 add(pane, BorderLayout.CENTER); 183 184 add(buildButtonRow(), BorderLayout.SOUTH); 185 186 // wire actions 187 // 188 historyTable.getSelectionModel().addListSelectionListener(showHistoryAction); 189 DataSet.selListeners.add(reloadAction); 190 } 191 192 public HistoryDialog() { 193 super(tr("History"), "history", tr("Display the history of all selected items."), 194 Shortcut.registerShortcut("subwindow:history", tr("Toggle: {0}", tr("History")), KeyEvent.VK_H, 195 Shortcut.GROUP_LAYER, Shortcut.SHIFT_DEFAULT), 150); 196 build(); 197 DataSet.selListeners.add(model); 198 } 199 200 /** 201 * refreshes the current list of history items; reloads history information from the server 202 */ 203 protected void refresh() { 204 HistoryLoadTask task = new HistoryLoadTask(); 205 Main.worker.execute(task); 206 } 207 208 /** 209 * shows the {@see HistoryBrowserDialog} for a given {@see History} 210 * 211 * @param h the history. Must not be null. 212 * @exception IllegalArgumentException thrown, if h is null 213 */ 214 protected void showHistory(History h) throws IllegalArgumentException { 215 if (h == null) 216 throw new IllegalArgumentException(tr("parameter ''{0}'' must not be null", "h")); 217 HistoryBrowserDialog dialog = getHistoryBrowserDialog(h.getId()); 218 if (dialog == null) { 219 dialog = new HistoryBrowserDialog(h); 220 } 221 dialog.setVisible(true); 222 } 223 224 /** 225 * invoked after the asynchronous {@see HistoryLoadTask} is finished. 226 * 227 * @param task the task which is calling back. 228 */ 229 protected void postRefresh(HistoryLoadTask task) { 230 model.refresh(); 231 if (task.isCancelled()) 232 return; 233 if (task.getLastException() != null) { 234 task.getLastException().printStackTrace(); 235 String msg = task.getLastException().getMessage(); 236 if (msg == null) { 237 msg = task.getLastException().toString(); 133 238 } 134 })); 135 buttons.add(new SideButton(marktr("Revert"), "revert", "History", 136 tr("Revert the state of all currently selected objects to the version selected in the history list."), new ActionListener(){ 137 public void actionPerformed(ActionEvent e) { 138 JOptionPane.showMessageDialog(Main.parent, tr("Not implemented yet.")); 239 JOptionPane.showMessageDialog( 240 Main.parent, 241 tr( 242 "<html>Failed to load history from the server. Details:<br>{0}</html>", 243 msg.replaceAll("&", "&").replaceAll(">", ">").replaceAll("<", "<") 244 ), 245 tr("Error"), 246 JOptionPane.ERROR_MESSAGE 247 ); 248 } 249 } 250 251 /** 252 * The table model with the history items 253 * 254 */ 255 class HistoryItemDataModel extends DefaultTableModel implements SelectionChangedListener{ 256 private ArrayList<History> data; 257 258 public HistoryItemDataModel() { 259 data = new ArrayList<History>(); 260 } 261 262 @Override 263 public int getRowCount() { 264 if (data == null) 265 return 0; 266 return data.size(); 267 } 268 269 @Override 270 public Object getValueAt(int row, int column) { 271 return data.get(row); 272 } 273 274 @Override 275 public boolean isCellEditable(int row, int column) { 276 return false; 277 } 278 279 public void refresh() { 280 data.clear(); 281 for (OsmPrimitive primitive: Main.ds.getSelected()) { 282 if (primitive.id == 0) { 283 continue; 284 } 285 History h = HistoryDataSet.getInstance().getHistory(primitive.id); 286 if (h !=null) { 287 data.add(h); 288 } 139 289 } 140 })); 141 add(buttons, BorderLayout.SOUTH); 142 143 DataSet.selListeners.add(this); 144 } 145 146 147 @Override public void setVisible(boolean b) { 148 super.setVisible(b); 149 if (b) 150 update(); 151 } 152 153 154 public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) { 155 if (isVisible()) 156 update(); 157 } 158 159 /** 160 * Identify all new objects in the selection and if any, hide the list. 161 * Else, update the list with the selected items shown. 162 */ 163 private void update() { 164 Collection<OsmPrimitive> sel = Main.ds.getSelected(); 165 if (!cache.keySet().containsAll(sel)) { 166 historyPane.setVisible(false); 167 notLoaded.setVisible(true); 168 } else { 169 SortedSet<HistoryItem> orderedHistory = new TreeSet<HistoryItem>(); 170 for (OsmPrimitive osm : sel) 171 orderedHistory.addAll(cache.get(osm)); 172 data.setRowCount(0); 173 for (HistoryItem i : orderedHistory) 174 data.addRow(new Object[]{i.osm, DateUtils.fromDate(i.osm.getTimestamp()), i.visible}); 175 historyPane.setVisible(true); 176 notLoaded.setVisible(false); 177 } 178 } 179 180 void reload() { 181 JOptionPane.showMessageDialog(Main.parent, tr("Not implemented yet.")); 290 fireTableDataChanged(); 291 } 292 293 public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) { 294 refresh(); 295 } 296 297 public History get(int idx) throws IndexOutOfBoundsException { 298 if (idx < 0 || idx >= data.size()) 299 throw new IndexOutOfBoundsException(tr("index out of bounds Got {0}", idx)); 300 return data.get(idx); 301 } 302 } 303 304 305 /** 306 * The table cell renderer for the history items. 307 * 308 */ 309 class HistoryTableCellRenderer extends JLabel implements TableCellRenderer { 310 311 public final Color BGCOLOR_SELECTED = new Color(143,170,255); 312 313 private HashMap<OsmPrimitiveType, ImageIcon> icons; 314 315 public HistoryTableCellRenderer() { 316 setOpaque(true); 317 icons = new HashMap<OsmPrimitiveType, ImageIcon>(); 318 icons.put(OsmPrimitiveType.NODE, ImageProvider.get("data", "node")); 319 icons.put(OsmPrimitiveType.WAY, ImageProvider.get("data", "way")); 320 icons.put(OsmPrimitiveType.RELATION, ImageProvider.get("data", "relation")); 321 } 322 323 protected void renderIcon(History history) { 324 setIcon(icons.get(history.getEarliest().getType())); 325 } 326 327 protected void renderText(History h) { 328 setText(h.getEarliest().getType().getLocalizedDisplayNameSingular() + " " + h.getId()); 329 } 330 331 public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, 332 boolean hasFocus, int row, int column) { 333 History h = (History)value; 334 renderIcon(h); 335 renderText(h); 336 if (isSelected) { 337 setBackground(BGCOLOR_SELECTED); 338 } else { 339 setBackground(Color.WHITE); 340 } 341 return this; 342 } 343 } 344 345 /** 346 * The column model 347 */ 348 class HistoryTableColumnModel extends DefaultTableColumnModel { 349 protected void createColumns() { 350 TableColumn col = null; 351 HistoryTableCellRenderer renderer = new HistoryTableCellRenderer(); 352 // column 0 - History item 353 col = new TableColumn(0); 354 col.setHeaderValue(tr("History item")); 355 col.setCellRenderer(renderer); 356 addColumn(col); 357 } 358 359 public HistoryTableColumnModel() { 360 createColumns(); 361 } 362 } 363 364 /** 365 * The asynchronous task which loads history information for the currently selected 366 * primitives from the server. 367 * 368 */ 369 class HistoryLoadTask extends PleaseWaitRunnable { 370 371 private boolean cancelled = false; 372 private Exception lastException = null; 373 374 public HistoryLoadTask() { 375 super(tr("Load history"), true); 376 } 377 378 @Override 379 protected void cancel() { 380 OsmApi.getOsmApi().cancel(); 381 cancelled = true; 382 } 383 384 @Override 385 protected void finish() { 386 postRefresh(this); 387 } 388 389 /** 390 * update the title of the {@see PleaseWaitDialog} with information about 391 * which primitive is currently loaded 392 * 393 * @param primitive the primitive to be loaded 394 */ 395 protected void notifyStartLoadingHistory(final OsmPrimitive primitive) { 396 SwingUtilities.invokeLater( 397 new Runnable() { 398 public void run() { 399 Main.pleaseWaitDlg.setTitle( 400 tr("Loading history for {0} with id {1}", 401 OsmPrimitiveType.from(primitive).getLocalizedDisplayNameSingular(), 402 Long.toString(primitive.id) 403 ) 404 ); 405 } 406 } 407 ); 408 } 409 410 /** 411 * enables/disables interminate progress indication in the {@see PleaseWaitDialog} 412 * 413 * @param enabled true, if interminate progress indication is to enabled; false, otherwise 414 */ 415 protected void setInterminateEnabled(final boolean enabled) { 416 SwingUtilities.invokeLater( 417 new Runnable() { 418 public void run() { 419 Main.pleaseWaitDlg.setIndeterminate(enabled); 420 } 421 } 422 ); 423 } 424 425 @Override 426 protected void realRun() throws SAXException, IOException, OsmTransferException { 427 Collection<OsmPrimitive> selection = Main.ds.getSelected(); 428 Iterator<OsmPrimitive> it = selection.iterator(); 429 setInterminateEnabled(true); 430 try { 431 while(it.hasNext()) { 432 OsmPrimitive primitive = it.next(); 433 if (cancelled) { 434 break; 435 } 436 if (primitive.id == 0) { 437 continue; 438 } 439 notifyStartLoadingHistory(primitive); 440 OsmServerHistoryReader reader = null; 441 HistoryDataSet ds = null; 442 try { 443 reader = new OsmServerHistoryReader(OsmPrimitiveType.from(primitive), primitive.id); 444 ds = reader.parseHistory(); 445 } catch(OsmTransferException e) { 446 if (cancelled) 447 return; 448 throw e; 449 } 450 HistoryDataSet.getInstance().mergeInto(ds); 451 } 452 } catch(OsmTransferException e) { 453 lastException = e; 454 throw e; 455 } finally { 456 setInterminateEnabled(false); 457 } 458 } 459 460 public boolean isCancelled() { 461 return cancelled; 462 } 463 464 public Exception getLastException() { 465 return lastException; 466 } 467 } 468 469 /** 470 * The action for reloading history information of the currently selected primitives. 471 * 472 */ 473 class ReloadAction extends AbstractAction implements SelectionChangedListener { 474 public ReloadAction() { 475 putValue(Action.SMALL_ICON, ImageProvider.get("dialogs","refresh")); 476 putValue(Action.SHORT_DESCRIPTION, tr("Reload all currently selected objects and refresh the list.")); 477 } 478 479 public void actionPerformed(ActionEvent e) { 480 refresh(); 481 } 482 483 public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) { 484 setEnabled(Main.ds.getSelected().size() > 0); 485 486 } 487 } 488 489 /** 490 * The action for showing history information of the current history item. 491 */ 492 class ShowHistoryAction extends AbstractAction implements ListSelectionListener { 493 public ShowHistoryAction() { 494 //putValue(Action.SMALL_ICON, ImageProvider.get("dialogs","refresh")); 495 putValue(Action.NAME, tr("Show")); 496 putValue(Action.SHORT_DESCRIPTION, tr("Display the history of the selected primitive")); 497 } 498 499 public void actionPerformed(ActionEvent e) { 500 int row = historyTable.getSelectionModel().getMinSelectionIndex(); 501 if (row < 0) return; 502 History h = model.get(row); 503 showHistory(h); 504 } 505 506 public void valueChanged(ListSelectionEvent e) { 507 setEnabled(historyTable.getSelectionModel().getMinSelectionIndex() >= 0); 508 } 182 509 } 183 510 }
Note:
See TracChangeset
for help on using the changeset viewer.