Changeset 2019 in josm


Ignore:
Timestamp:
2009-08-31T08:06:25+02:00 (13 years ago)
Author:
Gubaer
Message:

Improved history feature

Location:
trunk/src/org/openstreetmap/josm
Files:
3 added
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/data/osm/history/HistoryDataSet.java

    r1709 r2019  
    77import java.util.HashMap;
    88import java.util.NoSuchElementException;
     9import java.util.concurrent.CopyOnWriteArrayList;
    910
     11/**
     12 * A data set holding histories of OSM primitives.
     13 *
     14 *
     15 */
    1016public class HistoryDataSet {
    1117
     18    /** the unique instance */
    1219    private static HistoryDataSet historyDataSet;
    1320
     21    /**
     22     * Replies the unique instance of the history data set
     23     *
     24     * @return the unique instance of the history data set
     25     */
    1426    public static HistoryDataSet getInstance() {
    1527        if (historyDataSet == null) {
     
    1931    }
    2032
     33    /** the history data */
    2134    private HashMap<Long, ArrayList<HistoryOsmPrimitive>> data;
     35    private CopyOnWriteArrayList<HistoryDataSetListener> listeners;
    2236
    2337    public HistoryDataSet() {
    2438        data = new HashMap<Long, ArrayList<HistoryOsmPrimitive>>();
     39        listeners = new CopyOnWriteArrayList<HistoryDataSetListener>();
    2540    }
    2641
    27     public HistoryOsmPrimitive get(long id, long version) {
     42    public void addHistoryDataSetListener(HistoryDataSetListener listener) {
     43        synchronized(listeners) {
     44            if (!listeners.contains(listener)) {
     45                listeners.add(listener);
     46            }
     47        }
     48    }
     49
     50    public void removeHistoryDataSetListener(HistoryDataSetListener listener) {
     51        synchronized(listeners) {
     52            if (listeners.contains(listener)) {
     53                listeners.remove(listener);
     54            }
     55        }
     56    }
     57
     58    protected void fireHistoryUpdated(long id) {
     59        for (HistoryDataSetListener l : listeners) {
     60            l.historyUpdated(this, id);
     61        }
     62    }
     63
     64    /**
     65     * Replies the history primitive for the primitive with id <code>id</code>
     66     * and version <code>version</code>
     67     *
     68     * @param id the id of the primitive
     69     * @param version the version of the primitive
     70     * @return the history primitive for the primitive with id <code>id</code>
     71     * and version <code>version</code>
     72     * @throws NoSuchElementException thrown if this dataset doesn't include the respective
     73     * history primitive
     74     */
     75    public HistoryOsmPrimitive get(long id, long version) throws NoSuchElementException{
    2876        ArrayList<HistoryOsmPrimitive> versions = data.get(id);
    2977        if (versions == null)
     
    3785    }
    3886
     87    /**
     88     * Adds a history primitive to the data set
     89     *
     90     * @param primitive  the history primitive to add
     91     */
    3992    public void put(HistoryOsmPrimitive primitive) {
    4093        if (data.get(primitive.getId()) == null) {
     
    4295        }
    4396        data.get(primitive.getId()).add(primitive);
     97        fireHistoryUpdated(primitive.getId());
    4498    }
    4599
     
    66120            return;
    67121        for (Long id : other.data.keySet()) {
    68             if (!this.data.keySet().contains(id)) {
    69                 this.data.put(id, other.data.get(id));
    70             }
     122            this.data.put(id, other.data.get(id));
    71123        }
     124        fireHistoryUpdated(0);
    72125    }
    73126}
  • trunk/src/org/openstreetmap/josm/gui/dialogs/HistoryDialog.java

    r2017 r2019  
    4444import org.openstreetmap.josm.data.osm.history.History;
    4545import org.openstreetmap.josm.data.osm.history.HistoryDataSet;
     46import org.openstreetmap.josm.data.osm.history.HistoryDataSetListener;
    4647import org.openstreetmap.josm.gui.PleaseWaitRunnable;
    4748import org.openstreetmap.josm.gui.SideButton;
    4849import org.openstreetmap.josm.gui.history.HistoryBrowserDialog;
     50import org.openstreetmap.josm.gui.history.HistoryBrowserDialogManager;
     51import org.openstreetmap.josm.gui.history.HistoryLoadTask;
    4952import org.openstreetmap.josm.io.OsmApi;
    5053import org.openstreetmap.josm.io.OsmApiException;
     
    6770 * @author imi
    6871 */
    69 public class HistoryDialog extends ToggleDialog {
    70 
    71     /** the registry of history browser dialogs which are currently displaying */
    72     static private HashMap<Long, HistoryBrowserDialog> historyBrowserDialogs;
    73 
    74     /**
    75      * registers a {@see HistoryBrowserDialog}
    76      * @param id the id of the primitive dialog shows the history for
    77      * @param dialog the dialog
    78      */
    79     public static void registerHistoryBrowserDialog(long id, HistoryBrowserDialog dialog) {
    80         if (historyBrowserDialogs == null) {
    81             historyBrowserDialogs = new HashMap<Long, HistoryBrowserDialog>();
    82         }
    83         historyBrowserDialogs.put(id, dialog);
    84     }
    85 
    86     /**
    87      * unregisters a {@see HistoryBrowserDialog}
    88      * @param id the id of the primitive whose history dialog is to be unregistered
    89      *
    90      */
    91     public static void unregisterHistoryBrowserDialog(long id) {
    92         if (historyBrowserDialogs == null)
    93             return;
    94         historyBrowserDialogs.remove(id);
    95     }
    96 
    97     /**
    98      * replies the history dialog for the primitive with id <code>id</code>; null, if
    99      * no such {@see HistoryBrowserDialog} is currently showing
    100      *
    101      * @param id the id of the primitive
    102      * @return the dialog; null, if no such dialog is showing
    103      */
    104     public static HistoryBrowserDialog getHistoryBrowserDialog(long id) {
    105         if (historyBrowserDialogs == null)
    106             return null;
    107         return historyBrowserDialogs.get(id);
    108     }
    109 
     72public class HistoryDialog extends ToggleDialog implements HistoryDataSetListener {
    11073
    11174    /** the table model */
     
    197160        build();
    198161        DataSet.selListeners.add(model);
    199     }
    200 
    201     /**
    202      * refreshes the current list of history items; reloads history information from the server
    203      */
    204     protected void refresh() {
    205         HistoryLoadTask task = new HistoryLoadTask();
    206         Main.worker.execute(task);
     162        HistoryDataSet.getInstance().addHistoryDataSetListener(this);
     163    }
     164
     165
     166
     167    public void historyUpdated(HistoryDataSet source, long primitiveId) {
     168        model.refresh();
    207169    }
    208170
     
    216178        if (h == null)
    217179            throw new IllegalArgumentException(tr("parameter ''{0}'' must not be null", "h"));
    218         HistoryBrowserDialog dialog = getHistoryBrowserDialog(h.getId());
    219         if (dialog == null) {
    220             dialog = new HistoryBrowserDialog(h);
    221         }
    222         dialog.setVisible(true);
    223     }
    224 
    225     /**
    226      * invoked after the asynchronous {@see HistoryLoadTask} is finished.
    227      *
    228      * @param task the task which is calling back.
    229      */
    230     protected void postRefresh(HistoryLoadTask task) {
    231         model.refresh();
    232         if (task.isCancelled())
    233             return;
    234         if (task.getLastException() != null) {
    235             task.getLastException().printStackTrace();
    236             String msg = null;
    237             if (task.getLastException() instanceof OsmApiException) {
    238                 msg = ((OsmApiException)task.getLastException()).getErrorBody();
    239                 if (msg == null) {
    240                     msg = ((OsmApiException)task.getLastException()).getErrorHeader();
    241                 }
    242             }
    243             if (msg == null) {
    244                 msg = task.getLastException().getMessage();
    245             }
    246             if (msg == null) {
    247                 msg = task.getLastException().toString();
    248             }
    249             JOptionPane.showMessageDialog(
    250                     Main.parent,
    251                     tr(
    252                             "<html>Failed to load history from the server. Details:<br>{0}</html>",
    253                             msg.replaceAll("&", "&amp;").replaceAll(">", "&gt;").replaceAll("<", "&lt;")
    254                     ),
    255                     tr("Error"),
    256                     JOptionPane.ERROR_MESSAGE
    257             );
    258         }
    259     }
     180        if (HistoryBrowserDialogManager.getInstance().existsDialog(h.getId())) {
     181            HistoryBrowserDialogManager.getInstance().show(h.getId());
     182        } else {
     183            HistoryBrowserDialog dialog = new HistoryBrowserDialog(h);
     184            HistoryBrowserDialogManager.getInstance().show(h.getId(), dialog);
     185        }
     186    }
     187
    260188
    261189    /**
     
    340268            String msg = "";
    341269            switch(h.getEarliest().getType()) {
    342             case NODE:  msg = marktr("Node {0}"); break;
    343             case WAY: msg = marktr("Way {0}"); break;
    344             case RELATION: msg = marktr("Relation {0}"); break;
     270                case NODE:  msg = marktr("Node {0}"); break;
     271                case WAY: msg = marktr("Way {0}"); break;
     272                case RELATION: msg = marktr("Relation {0}"); break;
    345273            }
    346274            setText(tr(msg,h.getId()));
     
    381309
    382310    /**
    383      * The asynchronous task which loads history information for  the currently selected
    384      * primitives from the server.
    385      *
    386      */
    387     class HistoryLoadTask extends PleaseWaitRunnable {
    388 
    389         private boolean cancelled = false;
    390         private Exception lastException  = null;
    391 
    392         public HistoryLoadTask() {
    393             super(tr("Load history"), true);
    394         }
    395 
    396         @Override
    397         protected void cancel() {
    398             OsmApi.getOsmApi().cancel();
    399             cancelled = true;
    400         }
    401 
    402         @Override
    403         protected void finish() {
    404             postRefresh(this);
    405         }
    406 
    407         @Override
    408         protected void realRun() throws SAXException, IOException, OsmTransferException {
    409             Collection<OsmPrimitive> selection = Main.main.getCurrentDataSet().getSelected();
    410             Iterator<OsmPrimitive> it = selection.iterator();
    411             try {
    412                 while(it.hasNext()) {
    413                     OsmPrimitive primitive = it.next();
    414                     if (cancelled) {
    415                         break;
    416                     }
    417                     if (primitive.id == 0) {
    418                         continue;
    419                     }
    420                     String msg = "";
    421                     switch(OsmPrimitiveType.from(primitive)) {
    422                     case NODE: msg = marktr("Loading history for node {0}"); break;
    423                     case WAY: msg = marktr("Loading history for way {0}"); break;
    424                     case RELATION: msg = marktr("Loading history for relation {0}"); break;
    425                     }
    426                     progressMonitor.indeterminateSubTask(tr(msg,
    427                             Long.toString(primitive.id)));
    428                     OsmServerHistoryReader reader = null;
    429                     HistoryDataSet ds = null;
    430                     try {
    431                         reader = new OsmServerHistoryReader(OsmPrimitiveType.from(primitive), primitive.id);
    432                         ds = reader.parseHistory(progressMonitor.createSubTaskMonitor(1, false));
    433                     } catch(OsmTransferException e) {
    434                         if (cancelled)
    435                             return;
    436                         throw e;
    437                     }
    438                     HistoryDataSet.getInstance().mergeInto(ds);
    439                 }
    440             } catch(OsmTransferException e) {
    441                 lastException = e;
    442                 return;
    443             }
    444         }
    445 
    446         public boolean isCancelled() {
    447             return cancelled;
    448         }
    449 
    450         public Exception getLastException() {
    451             return lastException;
    452         }
    453     }
    454 
    455     /**
    456311     * The action for reloading history information of the currently selected primitives.
    457312     *
     
    464319
    465320        public void actionPerformed(ActionEvent e) {
    466             refresh();
     321            HistoryLoadTask task = new HistoryLoadTask();
     322            task.add(Main.main.getCurrentDataSet().getSelected());
     323            Main.worker.execute(task);
    467324        }
    468325
     
    473330                setEnabled(Main.main.getCurrentDataSet().getSelected().size() > 0);
    474331            }
    475 
    476332        }
    477333    }
  • trunk/src/org/openstreetmap/josm/gui/history/HistoryBrowserDialog.java

    r2017 r2019  
    88import java.awt.FlowLayout;
    99import java.awt.event.ActionEvent;
     10import java.awt.event.WindowAdapter;
     11import java.awt.event.WindowEvent;
    1012
    1113import javax.swing.AbstractAction;
    12 import javax.swing.JButton;
    1314import javax.swing.JDialog;
    1415import javax.swing.JOptionPane;
     
    1718import org.openstreetmap.josm.Main;
    1819import org.openstreetmap.josm.data.osm.history.History;
     20import org.openstreetmap.josm.data.osm.history.HistoryDataSet;
     21import org.openstreetmap.josm.data.osm.history.HistoryDataSetListener;
     22import org.openstreetmap.josm.gui.SideButton;
    1923import org.openstreetmap.josm.gui.dialogs.HistoryDialog;
     24import org.openstreetmap.josm.tools.ImageProvider;
    2025
    2126/**
     
    2429 *
    2530 */
    26 public class HistoryBrowserDialog extends JDialog {
     31public class HistoryBrowserDialog extends JDialog implements HistoryDataSetListener{
    2732
    2833    /** the embedded browser */
     
    3742        String title = "";
    3843        switch(h.getEarliest().getType()) {
    39         case NODE:  title = marktr("History for node {0}"); break;
    40         case WAY: title = marktr("History for way {0}"); break;
    41         case RELATION:  title = marktr("History for relation {0}"); break;
     44            case NODE:  title = marktr("History for node {0}"); break;
     45            case WAY: title = marktr("History for way {0}"); break;
     46            case RELATION:  title = marktr("History for relation {0}"); break;
    4247        }
    4348        setTitle(tr(
     
    5762
    5863        JPanel pnl = new JPanel();
    59         pnl.setLayout(new FlowLayout(FlowLayout.RIGHT));
     64        pnl.setLayout(new FlowLayout(FlowLayout.CENTER));
    6065
    61         JButton btn = new JButton(new CloseAction());
     66        SideButton btn = new SideButton(new ReloadAction());
     67        btn.setName("btn.reload");
     68        pnl.add(btn);
     69
     70        btn = new SideButton(new CloseAction());
    6271        btn.setName("btn.close");
    6372        pnl.add(btn);
     
    7786        setHistory(history);
    7887        renderTitle(history);
     88        HistoryDataSet.getInstance().addHistoryDataSetListener(this);
     89        addWindowListener(new WindowClosingAdapter());
    7990    }
    8091
     
    8798    }
    8899
    89     /**
    90      * registers this dialog with the registry of history dialogs
    91      *
    92      * @see HistoryDialog#registerHistoryBrowserDialog(long, HistoryBrowserDialog)
    93      */
    94     protected void register() {
    95         HistoryDialog.registerHistoryBrowserDialog(browser.getHistory().getId(), this);
    96     }
    97 
    98     /**
    99      * unregisters this dialog from the registry of history dialogs
    100      *
    101      * @see HistoryDialog#unregisterHistoryBrowserDialog(long)
    102      */
    103     protected void unregister() {
    104         HistoryDialog.unregisterHistoryBrowserDialog(browser.getHistory().getId());
    105     }
    106 
    107     @Override
    108     public void setVisible(boolean visible) {
    109         if (visible) {
    110             register();
    111             toFront();
    112         } else {
    113             unregister();
     100    public void historyUpdated(HistoryDataSet source, long primitiveId) {
     101        if (primitiveId == browser.getHistory().getId()) {
     102            browser.populate(source.getHistory(primitiveId));
     103        } else if (primitiveId == 0) {
     104            browser.populate(source.getHistory(browser.getHistory().getId()));
    114105        }
    115         super.setVisible(visible);
    116106    }
    117107
     
    120110            putValue(NAME, tr("Close"));
    121111            putValue(SHORT_DESCRIPTION, tr("Close the dialog"));
     112            putValue(SMALL_ICON, ImageProvider.get("ok"));
    122113        }
    123114
    124115        public void actionPerformed(ActionEvent e) {
    125             setVisible(false);
     116            HistoryDataSet.getInstance().removeHistoryDataSetListener(HistoryBrowserDialog.this);
     117            HistoryBrowserDialogManager.getInstance().hide(HistoryBrowserDialog.this);
     118        }
     119    }
     120
     121    class ReloadAction extends AbstractAction {
     122        public ReloadAction() {
     123            putValue(NAME, tr("Reload"));
     124            putValue(SHORT_DESCRIPTION, tr("Reload the history from the server"));
     125            putValue(SMALL_ICON, ImageProvider.get("dialogs", "refresh"));
     126        }
     127
     128        public void actionPerformed(ActionEvent e) {
     129            HistoryLoadTask task = new HistoryLoadTask();
     130            task.add(browser.getHistory());
     131            Main.worker.submit(task);
     132        }
     133    }
     134
     135    class WindowClosingAdapter extends WindowAdapter {
     136        @Override
     137        public void windowClosing(WindowEvent e) {
     138            HistoryDataSet.getInstance().removeHistoryDataSetListener(HistoryBrowserDialog.this);
     139            HistoryBrowserDialogManager.getInstance().hide(HistoryBrowserDialog.this);
    126140        }
    127141    }
  • trunk/src/org/openstreetmap/josm/gui/history/HistoryBrowserModel.java

    r1709 r2019  
    103103        setChanged();
    104104        notifyObservers();
     105        versionTableModel.fireTableDataChanged();
    105106    }
    106107
  • trunk/src/org/openstreetmap/josm/gui/history/VersionTable.java

    r1709 r2019  
    5656        public void mouseClicked(MouseEvent e) {
    5757            switch(e.getClickCount()) {
    58             case 2: handleDoubleClick(e); break;
     58                case 2: handleDoubleClick(e); break;
    5959            }
    6060        }
Note: See TracChangeset for help on using the changeset viewer.