Ignore:
Timestamp:
2009-11-14T17:59:10+01:00 (14 years ago)
Author:
Gubaer
Message:

fixed #3352: History doesn't get invalidated on upload?
fixed #3912: Extend history dialog to contain the currently modified version
new: zoom to node in list of nodes in history dialog (popup menu)
new: load history of node from node list in history dialog (popup menu or double click)
fixed: close all history dialogs when the number of layers drop to 0
fixed: implemented equals() and hashCode() on SimplePrimitiveId
fixed: history features now usePrimitiveId instead of long.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/gui/history/HistoryBrowserModel.java

    r2243 r2448  
    55
    66import java.util.ArrayList;
     7import java.util.Collection;
    78import java.util.Collections;
    89import java.util.HashSet;
     
    1213import javax.swing.table.DefaultTableModel;
    1314
    14 import org.openstreetmap.josm.data.coor.CoordinateFormat;
    15 import org.openstreetmap.josm.data.coor.LatLon;
     15import org.openstreetmap.josm.Main;
     16import org.openstreetmap.josm.data.osm.DataSetListener;
     17import org.openstreetmap.josm.data.osm.Node;
     18import org.openstreetmap.josm.data.osm.OsmPrimitive;
    1619import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
     20import org.openstreetmap.josm.data.osm.PrimitiveId;
     21import org.openstreetmap.josm.data.osm.Relation;
     22import org.openstreetmap.josm.data.osm.RelationMember;
     23import org.openstreetmap.josm.data.osm.SimplePrimitiveId;
     24import org.openstreetmap.josm.data.osm.Way;
    1725import org.openstreetmap.josm.data.osm.history.History;
    1826import org.openstreetmap.josm.data.osm.history.HistoryNode;
     
    2028import org.openstreetmap.josm.data.osm.history.HistoryRelation;
    2129import org.openstreetmap.josm.data.osm.history.HistoryWay;
     30import org.openstreetmap.josm.data.osm.visitor.AbstractVisitor;
     31import org.openstreetmap.josm.gui.layer.DataChangeListener;
     32import org.openstreetmap.josm.gui.layer.Layer;
     33import org.openstreetmap.josm.gui.layer.OsmDataLayer;
     34import org.openstreetmap.josm.gui.layer.Layer.LayerChangeListener;
    2235
    2336/**
    2437 * This is the model used by the history browser.
    2538 *
    26  * The state this model manages consists of the following elements:
     39 * The model state consists of the following elements:
    2740 * <ul>
    2841 *   <li>the {@see History} of a specific {@see OsmPrimitive}</li>
     
    4659 * @see HistoryBrowser
    4760 */
    48 public class HistoryBrowserModel extends Observable {
     61public class HistoryBrowserModel extends Observable implements LayerChangeListener, DataSetListener, DataChangeListener {
    4962
    5063    private static Logger logger = Logger.getLogger(HistoryBrowserModel.class.getName());
     
    5467    private HistoryOsmPrimitive reference;
    5568    private HistoryOsmPrimitive current;
     69    /**
     70     * latest isn't a reference of history. It's a clone of the currently edited
     71     * {@see OsmPrimitive} in the current edit layer.
     72     */
     73    private HistoryOsmPrimitive latest;
    5674
    5775    private VersionTableModel versionTableModel;
     
    6381    private RelationMemberTableModel referenceRelationMemberTableModel;
    6482
     83    /**
     84     * constructor
     85     */
    6586    public HistoryBrowserModel() {
    6687        versionTableModel = new VersionTableModel();
     
    7192        currentRelationMemberTableModel = new RelationMemberTableModel(PointInTimeType.CURRENT_POINT_IN_TIME);
    7293        referenceRelationMemberTableModel = new RelationMemberTableModel(PointInTimeType.REFERENCE_POINT_IN_TIME);
    73     }
    74 
     94
     95        if (getEditLayer() != null) {
     96            getEditLayer().data.addDataSetListener(this);
     97            getEditLayer().listenerDataChanged.add(this);
     98        }
     99        Layer.listeners.add(this);
     100
     101    }
     102
     103    /**
     104     * Creates a new history browser model for a given history.
     105     *
     106     * @param history the history. Must not be null.
     107     * @throws IllegalArgumentException thrown if history is null
     108     */
    75109    public HistoryBrowserModel(History history) {
    76110        this();
     111        if (history == null)
     112            throw new IllegalArgumentException(tr("Parameter ''{0}'' must not be null", "history"));
    77113        setHistory(history);
     114    }
     115
     116    /**
     117     * Replies the current edit layer; null, if there isn't a current edit layer
     118     * of type {@see OsmDataLayer}.
     119     *
     120     * @return the current edit layer
     121     */
     122    protected OsmDataLayer getEditLayer() {
     123        try {
     124            return Main.map.mapView.getEditLayer();
     125        } catch(NullPointerException e) {
     126            return null;
     127        }
    78128    }
    79129
     
    84134    public History getHistory() {
    85135        return history;
     136    }
     137
     138    protected boolean hasNewNodes(Way way) {
     139        for (Node n: way.getNodes()) {
     140            if (n.isNew()) return true;
     141        }
     142        return false;
     143    }
     144    protected boolean canShowAsLatest(OsmPrimitive primitive) {
     145        if (primitive == null) return false;
     146        if (primitive.isNew()) return false;
     147        if (history == null) return false;
     148        // only show latest of the same version if it is
     149        // modified
     150        if (history.getByVersion(primitive.getVersion()) != null)
     151            return primitive.isModified();
     152
     153        // latest has a higher version than one of the primitives
     154        // in the history (probably because the history got out of sync
     155        // with uploaded data) -> show the primitive as latest
     156        return true;
    86157    }
    87158
     
    97168            current = history.getEarliest();
    98169            reference = history.getEarliest();
     170            setLatest(null);
     171            if (getEditLayer() != null) {
     172                OsmPrimitive p = getEditLayer().data.getPrimitiveById(history.getId(), history.getType());
     173                if (canShowAsLatest(p)) {
     174                    HistoryOsmPrimitive latest = new HistoryPrimitiveBuilder().build(p);
     175                    setLatest(latest);
     176                }
     177            }
    99178        }
    100179        initTagTableModels();
    101180        fireModelChange();
    102181    }
    103 
    104182
    105183    protected void fireModelChange() {
     
    177255    }
    178256
     257    /**
     258     * Sets the {@see HistoryOsmPrimitive} which plays the role of a reference point
     259     * in time (see {@see PointInTimeType}).
     260     *
     261     * @param reference the reference history primitive. Must not be null.
     262     * @throws IllegalArgumentException thrown if reference is null
     263     * @throws IllegalStateException thrown if this model isn't a assigned a history yet
     264     * @throws IllegalArgumentException if reference isn't an history primitive for the history managed by this mode
     265     *
     266     * @see #setHistory(History)
     267     * @see PointInTimeType
     268     */
    179269    public void setReferencePointInTime(HistoryOsmPrimitive reference) throws IllegalArgumentException, IllegalStateException{
    180270        if (reference == null)
     
    196286    }
    197287
     288    /**
     289     * Sets the {@see HistoryOsmPrimitive} which plays the role of the current point
     290     * in time (see {@see PointInTimeType}).
     291     *
     292     * @param reference the reference history primitive. Must not be null.
     293     * @throws IllegalArgumentException thrown if reference is null
     294     * @throws IllegalStateException thrown if this model isn't a assigned a history yet
     295     * @throws IllegalArgumentException if reference isn't an history primitive for the history managed by this mode
     296     *
     297     * @see #setHistory(History)
     298     * @see PointInTimeType
     299     */
    198300    public void setCurrentPointInTime(HistoryOsmPrimitive current) throws IllegalArgumentException, IllegalStateException{
    199301        if (current == null)
     
    252354
    253355    /**
     356     * Returns true if <code>primitive</code> is the latest primitive
     357     * representing the version currently edited in the current data
     358     * layer.
     359     *
     360     * @param primitive the primitive to check
     361     * @return true if <code>primitive</code> is the latest primitive
     362     */
     363    public boolean isLatest(HistoryOsmPrimitive primitive) {
     364        if (primitive == null) return false;
     365        return primitive == latest;
     366    }
     367
     368    /**
    254369     * The table model for the list of versions in the current history
    255370     *
    256371     */
    257     public class VersionTableModel extends DefaultTableModel {
     372    public class VersionTableModel extends DefaultTableModel{
    258373
    259374        private VersionTableModel() {
     
    264379            if (history == null)
    265380                return 0;
    266             return history.getNumVersions();
     381            int ret = history.getNumVersions();
     382            if (latest != null) {
     383                ret++;
     384            }
     385            return ret;
    267386        }
    268387
     
    271390            if(history == null)
    272391                return null;
    273             return history.get(row);
     392            if (row < history.getNumVersions())
     393                return history.get(row);
     394            if (row == history.getNumVersions())
     395                return latest;
     396            return null;
    274397        }
    275398
     
    281404        public void setReferencePointInTime(int row) {
    282405            if (history == null) return;
     406            if (row == history.getNumVersions()) {
     407                if (latest != null) {
     408                    HistoryBrowserModel.this.setReferencePointInTime(latest);
     409                }
     410                return;
     411            }
    283412            if (row < 0 || row > history.getNumVersions()) return;
    284413            HistoryOsmPrimitive reference = history.get(row);
     
    288417        public void setCurrentPointInTime(int row) {
    289418            if (history == null) return;
     419            if (row == history.getNumVersions()) {
     420                if (latest != null) {
     421                    HistoryBrowserModel.this.setCurrentPointInTime(latest);
     422                }
     423                return;
     424            }
    290425            if (row < 0 || row > history.getNumVersions()) return;
    291426            HistoryOsmPrimitive current = history.get(row);
     
    295430        public boolean isReferencePointInTime(int row) {
    296431            if (history == null) return false;
     432            if (row == history.getNumVersions())
     433                return latest == reference;
    297434            if (row < 0 || row > history.getNumVersions()) return false;
    298435            HistoryOsmPrimitive p = history.get(row);
    299             return p.equals(reference);
     436            return p == reference;
    300437        }
    301438
    302439        public HistoryOsmPrimitive getPrimitive(int row) {
    303440            return history.get(row);
     441        }
     442
     443        public boolean isLatest(int row) {
     444            return row >= history.getNumVersions();
     445        }
     446
     447        public OsmPrimitive getLatest() {
     448            if (latest == null) return null;
     449            if (getEditLayer() == null) return null;
     450            OsmPrimitive p = getEditLayer().data.getPrimitiveById(latest.getId(), latest.getType());
     451            return p;
    304452        }
    305453    }
     
    467615                return null;
    468616            return way.getNodes().get(row);
     617        }
     618
     619        public PrimitiveId getNodeId(int row) {
     620            HistoryWay way = getWay();
     621            if (way == null) return null;
     622            if (row > way.getNumNodes()) return null;
     623            return new SimplePrimitiveId(way.getNodeId(row), OsmPrimitiveType.NODE);
    469624        }
    470625
     
    587742        }
    588743    }
     744
     745    protected void setLatest(HistoryOsmPrimitive latest) {
     746        if (latest == null) {
     747            if (this.current == this.latest) {
     748                this.current = history.getLatest();
     749            }
     750            if (this.reference == this.latest) {
     751                this.current = history.getLatest();
     752            }
     753            this.latest = null;
     754        } else {
     755            if (this.current == this.latest) {
     756                this.current = latest;
     757            }
     758            if (this.reference == this.latest) {
     759                this.reference = latest;
     760            }
     761            this.latest = latest;
     762        }
     763        fireModelChange();
     764    }
     765
     766    /**
     767     * Removes this model as listener for data change and layer change
     768     * events.
     769     *
     770     */
     771    public void unlinkAsListener() {
     772        if (getEditLayer() != null) {
     773            getEditLayer().data.removeDataSetListener(this);
     774        }
     775        Layer.listeners.remove(this);
     776
     777    }
     778
     779    /* ---------------------------------------------------------------------- */
     780    /* DataSetListener                                                        */
     781    /* ---------------------------------------------------------------------- */
     782    public void nodeMoved(Node node) {
     783        if (!node.isNew() && node.getId() == history.getId()) {
     784            setLatest(new HistoryPrimitiveBuilder().build(node));
     785        }
     786    }
     787
     788    public void primtivesAdded(Collection<? extends OsmPrimitive> added) {
     789        if (added == null || added.isEmpty()) return;
     790        for (OsmPrimitive p: added) {
     791            if (canShowAsLatest(p)) {
     792                setLatest(new HistoryPrimitiveBuilder().build(p));
     793            }
     794        }
     795    }
     796
     797    public void primtivesRemoved(Collection<? extends OsmPrimitive> removed) {
     798        if (removed == null || removed.isEmpty()) return;
     799        for (OsmPrimitive p: removed) {
     800            if (!p.isNew() && p.getId() == history.getId()) {
     801                setLatest(null);
     802            }
     803        }
     804    }
     805
     806    public void relationMembersChanged(Relation r) {
     807        if (!r.isNew() && r.getId() == history.getId()) {
     808            setLatest(new HistoryPrimitiveBuilder().build(r));
     809        }
     810    }
     811
     812    public void tagsChanged(OsmPrimitive prim) {
     813        if (!prim.isNew() && prim.getId() == history.getId()) {
     814            setLatest(new HistoryPrimitiveBuilder().build(prim));
     815        }
     816    }
     817
     818    public void wayNodesChanged(Way way) {
     819        if (!way.isNew() && way.getId() == history.getId()) {
     820            setLatest(new HistoryPrimitiveBuilder().build(way));
     821        }
     822    }
     823
     824    /* ---------------------------------------------------------------------- */
     825    /* DataChangeListener                                                    */
     826    /* ---------------------------------------------------------------------- */
     827    public void dataChanged(OsmDataLayer l) {
     828        if (l != getEditLayer()) return;
     829        OsmPrimitive primitive = l.data.getPrimitiveById(history.getId(), history.getType());
     830        HistoryOsmPrimitive latest;
     831        if (canShowAsLatest(primitive)) {
     832            latest = new HistoryPrimitiveBuilder().build(primitive);
     833        } else {
     834            latest = null;
     835        }
     836        setLatest(latest);
     837        fireModelChange();
     838    }
     839
     840    /* ---------------------------------------------------------------------- */
     841    /* LayerChangeListener                                                    */
     842    /* ---------------------------------------------------------------------- */
     843    public void activeLayerChange(Layer oldLayer, Layer newLayer) {
     844        if (oldLayer != null && oldLayer instanceof OsmDataLayer) {
     845            OsmDataLayer l = (OsmDataLayer)oldLayer;
     846            l.data.removeDataSetListener(this);
     847            l.listenerDataChanged.remove(this);
     848        }
     849        if (newLayer == null || ! (newLayer instanceof OsmDataLayer)) {
     850            latest = null;
     851            fireModelChange();
     852            return;
     853        }
     854        OsmDataLayer l = (OsmDataLayer)newLayer;
     855        l.data.addDataSetListener(this);
     856        l.listenerDataChanged.add(this);
     857        OsmPrimitive primitive = l.data.getPrimitiveById(history.getId(), history.getType());
     858        HistoryOsmPrimitive latest;
     859        if (canShowAsLatest(primitive)) {
     860            latest = new HistoryPrimitiveBuilder().build(primitive);
     861        } else {
     862            latest = null;
     863        }
     864        setLatest(latest);
     865        fireModelChange();
     866    }
     867
     868    public void layerAdded(Layer newLayer) {}
     869    public void layerRemoved(Layer oldLayer) {}
     870
     871    /**
     872     * Creates a {@see HistoryOsmPrimitive} from a {@see OsmPrimitive}
     873     *
     874     */
     875    class HistoryPrimitiveBuilder extends AbstractVisitor {
     876        private HistoryOsmPrimitive clone;
     877
     878        public void visit(Node n) {
     879            clone = new HistoryNode(n.getId(), n.getVersion(), n.isVisible(),n.getUser().getName(), n.getUser().getId(), 0, n.getTimestamp(), n.getCoor());
     880            clone.setTags(n.getKeys());
     881        }
     882
     883        public void visit(Relation r) {
     884            clone = new HistoryRelation(r.getId(), r.getVersion(), r.isVisible(),r.getUser().getName(), r.getUser().getId(), 0, r.getTimestamp());
     885            clone.setTags(r.getKeys());
     886            HistoryRelation hr = (HistoryRelation)clone;
     887            for (RelationMember rm : r.getMembers()) {
     888                hr.addMember(new org.openstreetmap.josm.data.osm.history.RelationMember(rm.getRole(), rm.getType(), rm.getUniqueId()));
     889            }
     890        }
     891
     892        public void visit(Way w) {
     893            clone = new HistoryWay(w.getId(), w.getVersion(), w.isVisible(),w.getUser().getName(), w.getUser().getId(), 0, w.getTimestamp());
     894            clone.setTags(w.getKeys());
     895            for (Node n: w.getNodes()) {
     896                ((HistoryWay)clone).addNode(n.getUniqueId());
     897            }
     898        }
     899
     900        public HistoryOsmPrimitive build(OsmPrimitive primitive) {
     901            primitive.visit(this);
     902            return clone;
     903        }
     904    }
    589905}
Note: See TracChangeset for help on using the changeset viewer.