001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.data.notes; 003 004import static org.openstreetmap.josm.tools.I18n.tr; 005 006import java.util.ArrayList; 007import java.util.Comparator; 008import java.util.Date; 009import java.util.List; 010import java.util.Objects; 011 012import org.openstreetmap.josm.data.coor.LatLon; 013import org.openstreetmap.josm.tools.date.DateUtils; 014 015/** 016 * A map note. It always has at least one comment since a comment is required to create a note on osm.org. 017 * @since 7451 018 */ 019public class Note { 020 021 /** Note state */ 022 public enum State { 023 /** Note is open */ 024 OPEN, 025 /** Note is closed */ 026 CLOSED 027 } 028 029 /** 030 * Sorts notes in the following order: 031 * 1) Open notes 032 * 2) Closed notes 033 * 3) New notes 034 * Within each subgroup it sorts by ID 035 */ 036 public static final Comparator<Note> DEFAULT_COMPARATOR = (n1, n2) -> { 037 if (n1.getId() < 0 && n2.getId() > 0) { 038 return 1; 039 } 040 if (n1.getId() > 0 && n2.getId() < 0) { 041 return -1; 042 } 043 if (n1.getState() == State.CLOSED && n2.getState() == State.OPEN) { 044 return 1; 045 } 046 if (n1.getState() == State.OPEN && n2.getState() == State.CLOSED) { 047 return -1; 048 } 049 return Long.compare(Math.abs(n1.getId()), Math.abs(n2.getId())); 050 }; 051 052 /** Sorts notes strictly by creation date */ 053 public static final Comparator<Note> DATE_COMPARATOR = (n1, n2) -> n1.createdAt.compareTo(n2.createdAt); 054 055 /** Sorts notes by user, then creation date */ 056 public static final Comparator<Note> USER_COMPARATOR = (n1, n2) -> { 057 String n1User = n1.getFirstComment().getUser().getName(); 058 String n2User = n2.getFirstComment().getUser().getName(); 059 return n1User.equals(n2User) ? DATE_COMPARATOR.compare(n1, n2) : n1User.compareTo(n2User); 060 }; 061 062 /** Sorts notes by the last modified date */ 063 public static final Comparator<Note> LAST_ACTION_COMPARATOR = 064 (n1, n2) -> NoteComment.DATE_COMPARATOR.compare(n1.getLastComment(), n2.getLastComment()); 065 066 private long id; 067 private LatLon latLon; 068 private Date createdAt; 069 private Date closedAt; 070 private State state; 071 private List<NoteComment> comments = new ArrayList<>(); 072 073 /** 074 * Create a note with a given location 075 * @param latLon Geographic location of this note 076 */ 077 public Note(LatLon latLon) { 078 this.latLon = latLon; 079 } 080 081 /** 082 * Returns the unique OSM ID of this note. 083 * @return The unique OSM ID of this note 084 */ 085 public long getId() { 086 return id; 087 } 088 089 /** 090 * Sets note id. 091 * @param id OSM ID of this note 092 */ 093 public void setId(long id) { 094 this.id = id; 095 } 096 097 /** 098 * Returns the geographic location of the note. 099 * @return The geographic location of the note 100 */ 101 public LatLon getLatLon() { 102 return latLon; 103 } 104 105 /** 106 * Returns the date at which this note was submitted. 107 * @return Date that this note was submitted 108 */ 109 public Date getCreatedAt() { 110 return DateUtils.cloneDate(createdAt); 111 } 112 113 /** 114 * Sets date at which this note has been created. 115 * @param createdAt date at which this note has been created 116 */ 117 public void setCreatedAt(Date createdAt) { 118 this.createdAt = DateUtils.cloneDate(createdAt); 119 } 120 121 /** 122 * Returns the date at which this note was closed. 123 * @return Date that this note was closed. Null if it is still open. 124 */ 125 public Date getClosedAt() { 126 return DateUtils.cloneDate(closedAt); 127 } 128 129 /** 130 * Sets date at which this note has been closed. 131 * @param closedAt date at which this note has been closed 132 */ 133 public void setClosedAt(Date closedAt) { 134 this.closedAt = DateUtils.cloneDate(closedAt); 135 } 136 137 /** 138 * Returns the open or closed state of this note. 139 * @return The open or closed state of this note 140 */ 141 public State getState() { 142 return state; 143 } 144 145 /** 146 * Sets the note state. 147 * @param state note state (open or closed) 148 */ 149 public void setState(State state) { 150 this.state = state; 151 } 152 153 /** 154 * Returns the list of comments associated with this note. 155 * @return An ordered list of comments associated with this note 156 */ 157 public List<NoteComment> getComments() { 158 return comments; 159 } 160 161 /** 162 * Returns the last comment, or {@code null}. 163 * @return the last comment, or {@code null} 164 * @since 11821 165 */ 166 public NoteComment getLastComment() { 167 return comments.isEmpty() ? null : comments.get(comments.size()-1); 168 } 169 170 /** 171 * Adds a comment. 172 * @param comment note comment 173 */ 174 public void addComment(NoteComment comment) { 175 comments.add(comment); 176 } 177 178 /** 179 * Returns the comment that was submitted by the user when creating the note 180 * @return First comment object 181 */ 182 public NoteComment getFirstComment() { 183 return comments.isEmpty() ? null : comments.get(0); 184 } 185 186 /** 187 * Copies values from a new note into an existing one. Used after a note 188 * has been updated on the server and the local copy needs refreshing. 189 * @param note New values to copy 190 */ 191 public void updateWith(Note note) { 192 this.comments = note.comments; 193 this.createdAt = DateUtils.cloneDate(note.createdAt); 194 this.id = note.id; 195 this.state = note.state; 196 this.latLon = note.latLon; 197 } 198 199 @Override 200 public int hashCode() { 201 return Objects.hash(id); 202 } 203 204 @Override 205 public boolean equals(Object obj) { 206 if (this == obj) 207 return true; 208 if (obj == null || getClass() != obj.getClass()) 209 return false; 210 Note note = (Note) obj; 211 return id == note.id; 212 } 213 214 @Override 215 public String toString() { 216 return tr("Note") + ' ' + id + ": " + getFirstComment(); 217 } 218}