diff --git a/cave/com.raytheon.uf.viz.points/src/com/raytheon/uf/viz/points/PointRequest.java b/cave/com.raytheon.uf.viz.points/src/com/raytheon/uf/viz/points/PointRequest.java new file mode 100644 index 0000000000..205b511ec8 --- /dev/null +++ b/cave/com.raytheon.uf.viz.points/src/com/raytheon/uf/viz/points/PointRequest.java @@ -0,0 +1,91 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.uf.viz.points; + +import com.raytheon.uf.viz.points.data.GroupNode; +import com.raytheon.uf.viz.points.data.IPointNode; +import com.raytheon.uf.viz.points.data.Point; + +/** + * This class is used to queue actions to perform on a Point's localization + * file. + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Aug 23, 2012            rferrel     Initial creation
+ * 
+ * 
+ * + * @author rferrel + * @version 1.0 + */ + +public class PointRequest { + public static enum RequestType { + ADD, UPDATE, DELETE + }; + + private final RequestType type; + + private final IPointNode point; + + /** + * The constructor. + * + * @param type + * - Kind of request to perform + * @param point + * - The point to pefrom the request on. + */ + public PointRequest(RequestType type, IPointNode point) { + this.type = type; + // Duplicate the point to capture information as it exists at the time + // of the request. + if (point.isGroup()) { + this.point = new GroupNode((Point) point); + } else { + this.point = new Point((Point) point); + } + } + + public IPointNode getPoint() { + return point; + } + + public RequestType getType() { + return type; + } + + public String toString() { + StringBuilder sb = new StringBuilder("PointUpdatedMessage - "); + sb.append("type: ").append(type).append(", point: "); + if (point == null) { + sb.append("null\n"); + } else { + sb.append("\"").append(point.getName()).append("\", \"") + .append(point.getGroup()).append("\"\n"); + } + return sb.toString(); + } +} diff --git a/cave/com.raytheon.uf.viz.points/src/com/raytheon/uf/viz/points/PointsDataManager.java b/cave/com.raytheon.uf.viz.points/src/com/raytheon/uf/viz/points/PointsDataManager.java index f9bcaedf4f..cec894c14a 100644 --- a/cave/com.raytheon.uf.viz.points/src/com/raytheon/uf/viz/points/PointsDataManager.java +++ b/cave/com.raytheon.uf.viz.points/src/com/raytheon/uf/viz/points/PointsDataManager.java @@ -29,9 +29,9 @@ import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; +import java.util.LinkedList; import java.util.List; import java.util.Map; -import java.util.concurrent.atomic.AtomicBoolean; import javax.measure.converter.UnitConverter; import javax.measure.unit.NonSI; @@ -44,8 +44,6 @@ import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.ListenerList; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.Job; -import org.eclipse.jface.util.IPropertyChangeListener; -import org.eclipse.jface.util.PropertyChangeEvent; import org.eclipse.swt.graphics.RGB; import org.geotools.referencing.GeodeticCalculator; import org.geotools.referencing.datum.DefaultEllipsoid; @@ -68,12 +66,12 @@ import com.raytheon.uf.common.status.UFStatus.Priority; import com.raytheon.uf.viz.core.exception.VizException; import com.raytheon.uf.viz.core.localization.LocalizationManager; import com.raytheon.uf.viz.core.requests.ThriftClient; +import com.raytheon.uf.viz.points.PointRequest.RequestType; import com.raytheon.uf.viz.points.data.GroupNode; import com.raytheon.uf.viz.points.data.IPointNode; import com.raytheon.uf.viz.points.data.Point; import com.raytheon.uf.viz.points.data.PointNameChangeException; import com.raytheon.uf.viz.points.data.PointSize; -import com.raytheon.viz.core.CorePlugin; import com.vividsolutions.jts.geom.Coordinate; /** @@ -95,8 +93,7 @@ import com.vividsolutions.jts.geom.Coordinate; * @version 1.0 */ -public class PointsDataManager implements ILocalizationFileObserver, - IPropertyChangeListener { +public class PointsDataManager implements ILocalizationFileObserver { private static final transient IUFStatusHandler statusHandler = UFStatus .getHandler(PointsDataManager.class); @@ -130,41 +127,38 @@ public class PointsDataManager implements ILocalizationFileObserver, private Coordinate home; - private ListenerList homeListeners = new ListenerList(); + private final ListenerList homeListeners = new ListenerList(); private Coordinate wfoCenter; private String site; - private LocalizationContext userCtx; + private final LocalizationContext userCtx; - private LocalizationFile userToolsDir; + private final LocalizationFile userToolsDir; - private LocalizationFile pointsDir; - - private LocalizationFile prevLFile; - - private Point prevPoint; - - private int cntPointsToUpdate; - - private int cntPointsUpdated; - - private AtomicBoolean groupUpdate; + private final LocalizationFile pointsDir; private IPathManager pathMgr; + private LinkedList requestList; + + private final Map> childrenKeyMap; + /** - * Prior to deleting a group's directory we must delete all points and - * sub-groups and finally the GROUP_INFO file. The order the file names are - * received in a message to fileUpdatedFile() may not be in the same order - * the deletes are sent. This mapping allows tracking the pending deletes so - * we know when the directory can be deleted. The String is the group's key - * and the list is the files and sub-directories that need to be deleted. - * when a message comes in for a given file it is removed from the list. - * When the list is empty the group's directory is deleted. + * Prior to deleting a group's directory we must get the acknowledgment that + * all its children have been deleted otherwise the delete of the directory + * may fail. The key is the directory name to delete and the list is the + * files in the directory that we need to get acknowledgment they have been + * deleted. */ - private Map> pendingDeletes; + private final Map> groupDeleteMap; + + /** + * Job to handle performing changes to the Localization files to maintain + * points and groups. + */ + private Job processRequestJob; public static synchronized PointsDataManager getInstance() { if (theManager == null) { @@ -173,10 +167,10 @@ public class PointsDataManager implements ILocalizationFileObserver, return theManager; } + /** + * Private constructor to maintain singleton instance. + */ private PointsDataManager() { - cntPointsToUpdate = 0; - cntPointsUpdated = 0; - groupUpdate = new AtomicBoolean(false); site = LocalizationManager.getInstance().getCurrentSite(); pathMgr = PathManagerFactory.getPathManager(); @@ -189,10 +183,72 @@ public class PointsDataManager implements ILocalizationFileObserver, + File.separator + site); userToolsDir.addFileUpdatedObserver(this); - pendingDeletes = new HashMap>(); + childrenKeyMap = new HashMap>(); - CorePlugin.getDefault().getPreferenceStore() - .addPropertyChangeListener(this); + groupDeleteMap = new HashMap>(); + + requestList = new LinkedList(); + } + + /** + * Queue a request to be perform latter by processRequests. + * + * @param request + */ + private void queueRequest(PointRequest request) { + synchronized (requestList) { + requestList.add(request); + } + } + + /** + * This starts a job to process the request queue. + */ + private void processRequests() { + firePointChangeListeners(); + if (processRequestJob == null) { + processRequestJob = new Job("Point Requests") { + + @Override + protected IStatus run(IProgressMonitor monitor) { + PointRequest request = null; + while (true) { + synchronized (requestList) { + if (requestList.isEmpty()) { + processRequestJob = null; + break; + } + request = requestList.remove(); + } + + Point point = (Point) request.getPoint(); + switch (request.getType()) { + case ADD: + if (!point.isGroup()) { + storePoint(point); + } else { + Point parent = points.get(getParentKey(point)); + String parentPath = getPointDirName(parent); + createGroup(parentPath, point.getName()); + } + break; + case UPDATE: + Assert.isTrue(!point.isGroup()); + storePoint(point); + break; + case DELETE: + removePoint(point); + break; + default: + statusHandler.handle(Priority.ERROR, + "Unknown PointChangeType"); + } + } + return Status.OK_STATUS; + } + }; + processRequestJob.schedule(); + } } /** @@ -217,15 +273,9 @@ public class PointsDataManager implements ILocalizationFileObserver, Point point = getPointsMap().get(name); Assert.isNotNull(point, "Point not found for " + name); point.setCoordinate(coordinate); - String path = getPointDirName(point); - LocalizationFile dir = pathMgr.getLocalizationFile(userCtx, path); - storePoint(dir, point); - } - - public void setPoint(Point point) { - String path = getPointDirName(point); - LocalizationFile dir = pathMgr.getLocalizationFile(userCtx, path); - storePoint(dir, point); + PointRequest request = new PointRequest(RequestType.UPDATE, point); + queueRequest(request); + processRequests(); } /** @@ -276,6 +326,10 @@ public class PointsDataManager implements ILocalizationFileObserver, return pointNames; } + /** + * Store home coordinates in the root directory; fires an + * ILocalizationFileObserver event + */ private void storeHome() { Point point = new Point("home", 0.0, 0.0, true, false, false, new RGB( 0, 0, 0), ""); @@ -307,8 +361,6 @@ public class PointsDataManager implements ILocalizationFileObserver, try { marshalPointToXmlFile(point, lFile); - prevLFile = null; - prevPoint = null; } catch (Exception e) { statusHandler.handle(Priority.PROBLEM, e.getLocalizedMessage(), e); } @@ -331,41 +383,55 @@ public class PointsDataManager implements ILocalizationFileObserver, return getPointsMap().values(); } + /** + * This checks and if needed loads points. It will also check and create the + * default points and the group they belong to. + * + * @return points + */ private Map getPointsMap() { + boolean doRequest = false; if (points.isEmpty()) { - loadPoints(); - String dirPath = pointsDir.getName().trim(); - String name = D2D_POINTS_GROUP.replace(' ', - PointUtilities.DELIM_CHAR); - String path = dirPath + File.separator + name; - LocalizationFile d2dDir = pathMgr - .getLocalizationFile(userCtx, path); - boolean createPoints = true; - if (d2dDir.exists()) { + doRequest = loadPoints(); + String d2dKey = File.separator + D2D_POINTS_GROUP; + Point d2dPoint = points.get(d2dKey); + if (d2dPoint != null) { + if (childrenKeyMap.get(d2dKey).size() == 0) { + createDefaultPoints(); + processRequests(); + } + } else { + String dirPath = pointsDir.getName().trim(); + String name = D2D_POINTS_GROUP.replace(' ', + PointUtilities.DELIM_CHAR); + String path = dirPath + File.separator + name; + LocalizationFile d2dDir = pathMgr.getLocalizationFile(userCtx, + path); if (!d2dDir.isDirectory()) { try { d2dDir.delete(); - createGroup(dirPath, name); } catch (LocalizationOpFailedException e) { statusHandler.handle(Priority.PROBLEM, "Unable to create group: " + D2D_POINTS_GROUP); - createPoints = false; - } - } else { - LocalizationFile[] files = pathMgr.listFiles(userCtx, path, - new String[] { POINT_FILENAME_EXT }, true, false); - for (LocalizationFile lf : files) { - if (!lf.isDirectory()) { - createPoints = false; - break; - } + return points; } } - } else { - createGroup(dirPath, name); - } - if (createPoints) { + d2dPoint = new GroupNode(); + d2dPoint.setName(D2D_POINTS_GROUP); + d2dPoint.setGroup(d2dKey); + PointRequest request = new PointRequest(RequestType.ADD, + d2dPoint); + queueRequest(request); + String parentKey = ""; + childrenKeyMap.get(parentKey).add(d2dKey); + childrenKeyMap.put(d2dKey, new ArrayList()); + put(d2dKey, d2dPoint); createDefaultPoints(); + doRequest = true; + } + + if (doRequest) { + processRequests(); } } return points; @@ -375,14 +441,19 @@ public class PointsDataManager implements ILocalizationFileObserver, Coordinate center = getHome(); int baseRingSize = 120; int startAngle = -90; + String group = File.separator + D2D_POINTS_GROUP; + List d2dChildren = childrenKeyMap.get(group); for (char label = 'A'; label <= 'J'; label++) { String name = String.valueOf(label); Coordinate coordinate = getCoordinateOnCircle(center, baseRingSize, startAngle); Point point = new Point(name, coordinate, false, new RGB(0, 0, 0), - false, true, PointSize.DEFAULT, D2D_POINTS_GROUP); - setPoint(point); + false, true, PointSize.DEFAULT, group); + PointRequest request = new PointRequest(RequestType.ADD, point); + queueRequest(request); + put(name, point); + d2dChildren.add(name); startAngle += 36; } } @@ -407,7 +478,7 @@ public class PointsDataManager implements ILocalizationFileObserver, + File.separator + HOME_LOCATION_FILE); Point point = null; if (lFile.exists()) { - point = loadPoint(pointsDir, HOME_LOCATION_FILE); + point = loadPoint(lFile); } if (point == null) { @@ -419,8 +490,14 @@ public class PointsDataManager implements ILocalizationFileObserver, return home; } - private void loadPoints() { + /** + * Clear mapping of points and children and create all points and group + * nodes from the localization files and directory structure. + */ + private boolean loadPoints() { + boolean doRequest = false; points.clear(); + childrenKeyMap.clear(); String path = pointsDir.getName().trim(); LocalizationFile[] files = pathMgr.listFiles(userCtx, path, @@ -428,49 +505,52 @@ public class PointsDataManager implements ILocalizationFileObserver, if (files.length == 0) { pointsDir.getFile().mkdirs(); - Point point = new GroupNode("point"); - put(point.getGroup(), point); + Point point = new GroupNode(""); + String key = point.getGroup(); + PointRequest request = new PointRequest(RequestType.ADD, point); + queueRequest(request); + put(key, point); + childrenKeyMap.put(key, new ArrayList()); + doRequest = true; } else { - + Point point = null; for (LocalizationFile lf : files) { - prevPoint = loadPoint(lf); - put(getPointKey(lf), prevPoint); + point = loadPoint(lf); + String key = getPointKey(lf); + put(key, point); + if (point.isGroup()) { + childrenKeyMap.put(key, new ArrayList()); + } + if (key.length() > 0) { + // p + String parentKey = getParentKey(point); + childrenKeyMap.get(parentKey).add(key); + } } } + return doRequest; } /** - * Create a Point from a file; does NOT fire an ILocalizationFileObserver - * event. + * Parse a localization file and return the point it contains; does NOT fire + * an ILocalizationFileObserver event. * - * @param dir - * @param fileName + * @param lFile * @return point */ - private Point loadPoint(LocalizationFile dir, String fileName) { - - LocalizationFile lf = pathMgr.getLocalizationFile(dir.getContext(), dir - .getName().trim() + File.separator + fileName); - return loadPoint(lf); - } - private Point loadPoint(LocalizationFile lFile) { - if (prevLFile == lFile) { - return prevPoint; - } + Point point = null; if (lFile.isDirectory()) { String key = getPointKey(lFile); - prevPoint = points.get(key); - if (prevPoint == null) { - prevPoint = new GroupNode(getPointName(lFile)); - prevPoint.setGroup(key); + point = points.get(key); + if (point == null) { + point = new GroupNode(getPointName(lFile)); + point.setGroup(key); } - prevLFile = lFile; - return prevPoint; + return point; } - Point point = null; try { point = unmarshalPointFromXmlFile(lFile); } catch (IOException ex) { @@ -487,8 +567,6 @@ public class PointsDataManager implements ILocalizationFileObserver, } if (point != null) { - prevLFile = lFile; - prevPoint = point; StringBuffer sb = new StringBuffer(lFile.toString()); sb.replace(0, pointsDir.toString().length(), ""); int index = sb.lastIndexOf(File.separator); @@ -499,36 +577,60 @@ public class PointsDataManager implements ILocalizationFileObserver, } private LocalizationFile getGroupDir(Point point) { - String path = (pointsDir.getName() + point.getGroup()).replace(' ', - PointUtilities.DELIM_CHAR); + String path = (pointsDir.getName() + point.getGroup().replace(' ', + PointUtilities.DELIM_CHAR)); LocalizationFile dir = pathMgr.getLocalizationFile(userCtx, path); return dir; } - public List getChildren(IPointNode parent) { - if (parent == null) { - getPoints(); - return getChildrenPoints(pointsDir); - } - Point point = (Point) parent; - String path = getPointDirName(point); - LocalizationFile lFile = pathMgr.getLocalizationFile(userCtx, path); - return getChildrenPoints(lFile); + /** + * Get the points and non-empty group nodes that are the children of the + * node. + * + * @param node + * @return children + */ + public List getChildren(IPointNode node) { + return getChildren(node, false); } - private List getChildrenPoints(LocalizationFile lFile) { - List children = new ArrayList(); - LocalizationFile[] files = pathMgr.listFiles(userCtx, lFile.getName() - .trim(), new String[] { POINT_FILENAME_EXT }, false, false); - for (int index = 1; index < files.length; ++index) { - LocalizationFile lf = files[index]; - Point point = null; - point = points.get(getPointKey(lf)); - if (point != null) { - children.add(point); - } + /** + * Get children of node. When node is null the children of the root node are + * returned. + * + * @param node + * @param allGroups + * - When true include all groups otherwise only non-empty groups + * are included. + * @return children + */ + public List getChildren(IPointNode node, boolean allGroups) { + String parentKey = null; + if (node == null) { + parentKey = ""; + } else { + parentKey = getPointKey((Point) node); + } + + List childrenKeyList = childrenKeyMap.get(parentKey); + List children = new ArrayList(); + if (childrenKeyList != null) { + if (allGroups) { + for (String key : childrenKeyList) { + children.add(points.get(key)); + } + } else { + for (String key : childrenKeyList) { + IPointNode child = points.get(key); + if (!child.isGroup() + || childrenKeyMap.get(getPointKey((Point) child)) + .size() > 0) { + children.add(child); + } + } + } + sort(children); } - sort(children); return children; } @@ -543,11 +645,10 @@ public class PointsDataManager implements ILocalizationFileObserver, } /** - * Given a Point file name (e.g.map-point-Brooklyn~Bridge.txt) return the - * user's original name (e.g. Brooklyn Bridge) + * Get the localization file name for the point. * * @param point - * @return fileName + * @return filename */ private String getPointFilename(Point point) { StringBuilder sb = new StringBuilder(); @@ -559,12 +660,18 @@ public class PointsDataManager implements ILocalizationFileObserver, sb.append(point.getGroup()).append(File.separator) .append(POINT_FILENAME_PREFIX).append(point.getName()) .append(POINT_FILENAME_EXT); - String name = sb.toString().replace(' ', PointUtilities.DELIM_CHAR); - return name; + String filename = sb.toString().replace(' ', PointUtilities.DELIM_CHAR); + return filename; } - private String getPointDirName(Point point) { - String group = point.getGroup(); + /** + * Get the localization path for the group node. + * + * @param node + * @return path + */ + private String getPointDirName(Point node) { + String group = node.getGroup(); StringBuilder sb = new StringBuilder(); sb.append(pointsDir.getName().trim()); if (group.length() > 0) { @@ -573,10 +680,16 @@ public class PointsDataManager implements ILocalizationFileObserver, } sb.append(group); } - String name = sb.toString().replace(' ', PointUtilities.DELIM_CHAR); - return name; + String path = sb.toString().replace(' ', PointUtilities.DELIM_CHAR); + return path; } + /** + * Get the name for the point/node for the localization file. + * + * @param lFile + * @return name + */ private String getPointName(LocalizationFile lFile) { String name = null; StringBuilder sb = new StringBuilder(); @@ -591,6 +704,12 @@ public class PointsDataManager implements ILocalizationFileObserver, return name; } + /** + * Obtain the unique key for the point represented by the localization file. + * + * @param lFile + * @return key + */ private String getPointKey(LocalizationFile lFile) { String key = null; if (!lFile.isDirectory()) { @@ -599,31 +718,48 @@ public class PointsDataManager implements ILocalizationFileObserver, StringBuilder sb = new StringBuilder(); sb.append(lFile.toString()); sb.replace(0, pointsDir.toString().length(), ""); - key = sb.toString().replace(PointUtilities.DELIM_CHAR, ' '); + key = sb.toString(); + } + return key.replace(PointUtilities.DELIM_CHAR, ' '); + } + + /** + * Determine the key for the point. + * + * @param point + * @return key + */ + private String getPointKey(Point point) { + String key = null; + if (!point.isGroup()) { + key = point.getName(); + } else { + key = point.getGroup(); } return key; } + /** + * Get the key for the parent of the point. + * + * @param point + * @return parentKey + */ + private String getParentKey(Point point) { + String parentKey = point.getGroup(); + if (point.isGroup() && parentKey.length() > 0) { + parentKey = parentKey.substring(0, + parentKey.lastIndexOf(File.separator)); + } + return parentKey; + } + /** * @param node * @return */ public IPointNode getParent(IPointNode node) { - Point child = (Point) node; - StringBuilder sb = new StringBuilder(child.getGroup()); - if (child.isGroup()) { - // In a group node the getGroup() returns the full path to the - // group. It is used as the key to retrieve the node from the - // points map. Thus to get the parent key for the group node, - // /Towers/alt/sub, you strip off the last part of the node's - // key to get /Towers/alt. If the nodes key is empty this is the - // root node and there is no parent. - if (sb.length() > 0) { - sb.replace(sb.lastIndexOf(File.separator), sb.length(), ""); - } - } - Point parent = points.get(sb.toString().replace( - PointUtilities.DELIM_CHAR, ' ')); + Point parent = points.get(getParentKey((Point) node)); return new GroupNode(parent); } @@ -662,68 +798,56 @@ public class PointsDataManager implements ILocalizationFileObserver, } } String name = GROUP_TEMP_PREFIX + cnt; - return createGroup(path, name); - } - - private void doMoveGroup(IPointNode srcNode, IPointNode destNode) { - Point srcPoint = (Point) srcNode; - Point destPoint = (Point) destNode; - String srcPath = getPointDirName(srcPoint); - String destPath = getPointDirName(destPoint); - String destGroupName = destPoint.getGroup(); - LocalizationFile[] files = pathMgr.listFiles(userCtx, srcPath, - new String[] { POINT_FILENAME_EXT }, false, false); - Point point = null; - for (int index = 1; index < files.length; ++index) { - LocalizationFile lf = files[index]; - point = loadPoint(lf); - if (lf.isDirectory()) { - IPointNode child = createGroup(destPath, point.getName()); - doMoveGroup(point, child); - } else { - ++cntPointsToUpdate; - doDeletePoint(point); - point.setGroup(destGroupName); - doAddPoint(point); - } - } + Point node = new GroupNode(); + node.setName(name); + String parentKey = getPointKey(parent); + node.setGroup(parentKey + File.separator + name); + String nodeKey = getPointKey(node); + PointRequest request = new PointRequest(RequestType.ADD, node); + queueRequest(request); + childrenKeyMap.get(parentKey).add(nodeKey); + put(nodeKey, node); + childrenKeyMap.put(nodeKey, new ArrayList()); + processRequests(); + return node; } public void moveNode(final IPointNode node, final IPointNode destNode) { - if (!node.isGroup()) { - if (getParent(node).compareTo(destNode) != 0) { - synchronized (groupUpdate) { - groupUpdate.set(true); - Point point = (Point) node; - ++cntPointsToUpdate; - doDeletePoint(point); - point.setGroup(destNode.getGroup()); - doAddPoint(point); - waitForUpdate(); - groupUpdate.set(false); - firePointChangeListeners(); - } - } - } else { - Job job = new Job("moveNode Group") { + String oldParentKey = getParentKey((Point) node); + String destKey = getPointKey((Point) destNode); + if (oldParentKey.equals(destKey)) { + return; + } + doMoveNode(node, destNode); + processRequests(); + } - @Override - protected IStatus run(IProgressMonitor monitor) { - synchronized (groupUpdate) { - groupUpdate.set(true); - String parentPath = getPointDirName((Point) destNode); - IPointNode destGroup = createGroup(parentPath, - node.getName()); - doMoveGroup(node, destGroup); - doDeletePoint((Point) node); - waitForUpdate(); - firePointChangeListeners(); - groupUpdate.set(false); - } - return Status.OK_STATUS; - } - }; - job.schedule(); + private void doMoveNode(IPointNode node, IPointNode destNode) { + String key = getPointKey((Point) node); + Point point = points.get(key); + String newParentKey = getPointKey((Point) destNode); + if (!point.isGroup()) { + doDeletePoint(point); + point.setGroup(newParentKey); + doAddPoint(point); + put(key, point); + childrenKeyMap.get(newParentKey).add(key); + } else { + Point newGroup = new GroupNode((Point) destNode); + String newGroupKey = newParentKey + File.separator + + point.getName(); + newGroup.setName(point.getName()); + newGroup.setGroup(newGroupKey); + PointRequest request = new PointRequest(RequestType.ADD, newGroup); + queueRequest(request); + put(newGroupKey, newGroup); + childrenKeyMap.put(newGroupKey, new ArrayList()); + childrenKeyMap.get(newParentKey).add(newGroupKey); + + for (IPointNode child : getChildren(node)) { + doMoveNode(child, newGroup); + } + doDeletePoint(point); } } @@ -732,29 +856,22 @@ public class PointsDataManager implements ILocalizationFileObserver, return false; } - Job job = new Job("RENAME_GROUP") { - - @Override - protected IStatus run(IProgressMonitor monitor) { - IPointNode parent = getParent(srcNode); - String path = getPointDirName((Point) parent); - synchronized (groupUpdate) { - groupUpdate.set(true); - IPointNode destNode = createGroup(path, destName); - - if (destNode != null) { - doMoveGroup(srcNode, destNode); - doDeletePoint((Point) srcNode); - waitForUpdate(); - firePointChangeListeners(); - groupUpdate.set(false); - } - return Status.OK_STATUS; - } - } - - }; - job.schedule(); + String parentKey = getParentKey((Point) srcNode); + Point parent = points.get(parentKey); + Point destNode = new GroupNode(parent); + String destKey = parentKey + File.separator + destName; + destNode.setName(destName); + destNode.setGroup(destKey); + PointRequest request = new PointRequest(RequestType.ADD, destNode); + queueRequest(request); + put(destKey, destNode); + childrenKeyMap.get(parentKey).add(destKey); + childrenKeyMap.put(destKey, new ArrayList()); + for (IPointNode child : getChildren(srcNode)) { + doMoveNode(child, destNode); + } + doDeletePoint((Point) srcNode); + processRequests(); return true; } @@ -797,9 +914,6 @@ public class PointsDataManager implements ILocalizationFileObserver, outStream.write(gPoint.getGroup().getBytes()); outStream.close(); lf.save(); - if (groupUpdate.get()) { - ++cntPointsToUpdate; - } } catch (LocalizationException e) { statusHandler.handle(Priority.PROBLEM, "Unable to create the group: " + gPoint.getGroup(), e); @@ -863,76 +977,162 @@ public class PointsDataManager implements ILocalizationFileObserver, return; } - synchronized (groupUpdate) { - if (groupUpdate.get()) { - ++cntPointsUpdated; - pointsFileUpdated(message); - try { - // Let waitForUpdate know we updated the count. - groupUpdate.notify(); - } catch (IllegalMonitorStateException e) { - // Ignore - } - return; - } + // Assume message is for a directory (group), GROUP_INFO or point map + // file. If the changes are already in this instance of class then the + // message can be ignored. Otherwise we need to update this instance and + // notify listeners. + boolean stateChange = false; + if (fileName.startsWith(POINT_FILENAME_PREFIX) + && fileName.endsWith(POINT_FILENAME_EXT)) { + stateChange = checkPoint(message, fileName); + } else if (fileName.equals(GROUP_INFO)) { + stateChange = checkGroup(message); + } else if (message.getChangeType() == FileChangeType.DELETED) { + // Assume group directory that may be on the pending delete list. + checkGroupDelete(message); } - pointsFileUpdated(message); - firePointChangeListeners(); - } - - private void checkDelete(String filename) { - if (!filename.endsWith(GROUP_INFO)) { - LocalizationFile lFile = pathMgr.getLocalizationFile(userCtx, - filename); - remove(getPointKey(lFile)); - } - - // Decouple keys set from the mapping to allow removal without throwing - // ConcurrentModificationException. - List keys = new ArrayList(pendingDeletes.keySet()); - for (String key : keys) { - List pendList = pendingDeletes.get(key); - - if (pendList.contains(filename)) { - pendList.remove(filename); - // The group's directory is now empty and can be removed. - if (pendList.size() == 0) { - pendingDeletes.remove(key); - removePoint(points.get(key)); - } - return; - } + if (stateChange) { + firePointChangeListeners(); } } - private void pointsFileUpdated(FileUpdatedMessage message) { - String filename = message.getFileName(); - LocalizationFile lFile = pathMgr.getLocalizationFile(userCtx, filename); - if (!lFile.getName().startsWith(pointsDir.getName())) { - return; - } + private boolean checkPoint(FileUpdatedMessage message, String fileName) { + boolean stateChange = false; - FileChangeType type = message.getChangeType(); + StringBuilder sb = new StringBuilder(message.getFileName()); + sb.replace(0, pointsDir.getName().length(), ""); + sb.replace(sb.lastIndexOf(File.separator), sb.length(), ""); + String groupKey = sb.toString().replace(PointUtilities.DELIM_CHAR, ' '); - if (filename.endsWith(GROUP_INFO)) { - if (type == FileChangeType.DELETED) { - checkDelete(filename); - } else if (type == FileChangeType.ADDED) { - String groupFilename = filename.substring(0, - filename.lastIndexOf(File.separatorChar)); - LocalizationFile glFile = pathMgr.getLocalizationFile(userCtx, - groupFilename); - Point point = loadPoint(glFile); - put(getPointKey(glFile), point); + sb.setLength(0); + sb.append(fileName); + sb.replace(0, POINT_FILENAME_PREFIX.length(), ""); + sb.replace(sb.length() - POINT_FILENAME_EXT.length(), sb.length(), ""); + String key = sb.toString().replace(PointUtilities.DELIM_CHAR, ' '); + + Point foundPoint = points.get(key); + Point point = null; + LocalizationFile lFile = null; + switch (message.getChangeType()) { + case ADDED: + lFile = pathMgr.getLocalizationFile(userCtx, message.getFileName()); + point = loadPoint(lFile); + if (foundPoint == null) { + put(key, point); + childrenKeyMap.get(groupKey).add(key); + stateChange = true; + } else if (!groupKey.equals(foundPoint.getGroup())) { + // Finishing up moving the point to a different group. + childrenKeyMap.get(foundPoint.getGroup()).remove(key); + childrenKeyMap.get(groupKey).add(key); + put(key, point); + stateChange = true; } - } else { - - if (type == FileChangeType.DELETED) { - checkDelete(filename); + break; + case UPDATED: + lFile = pathMgr.getLocalizationFile(userCtx, message.getFileName()); + point = loadPoint(lFile); + if (foundPoint == null) { + statusHandler.handle(Priority.PROBLEM, + "Unable to find point to update: " + key); + } else if (!groupKey.equals(foundPoint.getGroup())) { + statusHandler.handle(Priority.PROBLEM, + "Updated point in wrong group: " + key); + } else if (point.differentContent(foundPoint)) { + put(key, point); + stateChange = true; + } + break; + case DELETED: + if (foundPoint != null) { + // When groups are different assume in the middle of move + // (delete/add) do nothing and let the ADDED handle it. + if (groupKey.equals(foundPoint.getGroup())) { + childrenKeyMap.get(groupKey).remove(key); + remove(key); + stateChange = true; + } } else { - Point point = loadPoint(lFile); - put(getPointKey(lFile), point); + checkGroupDelete(message); + } + break; + default: + statusHandler.handle(Priority.DEBUG, "Unhandled change type: " + + message.getChangeType()); + } + return stateChange; + } + + private boolean checkGroup(FileUpdatedMessage message) { + boolean stateChange = false; + StringBuilder sb = new StringBuilder(message.getFileName()); + sb.setLength(sb.lastIndexOf(File.separator)); + sb.replace(0, pointsDir.getName().length(), ""); + String key = sb.toString().replace(PointUtilities.DELIM_CHAR, ' '); + String parentKey = key.substring(0, key.lastIndexOf(File.separator)); + Point foundGroup = points.get(key); + + switch (message.getChangeType()) { + case ADDED: + if (foundGroup == null) { + sb.replace(0, sb.lastIndexOf(File.separator) + 1, ""); + String name = sb.toString().replace(PointUtilities.DELIM_CHAR, + ' '); + Point point = new GroupNode(); + point.setName(name); + point.setGroup(key); + put(key, point); + childrenKeyMap.get(parentKey).add(key); + childrenKeyMap.put(key, new ArrayList()); + stateChange = true; + } + break; + case DELETED: + if (foundGroup != null) { + if (childrenKeyMap.get(key).size() > 0) { + statusHandler.handle(Priority.PROBLEM, "Removing group \"" + + key + "\" while it contains points or groups"); + } + childrenKeyMap.remove(key); + childrenKeyMap.get(parentKey).remove(key); + remove(key); + stateChange = true; + } else { + checkGroupDelete(message); + } + break; + default: + statusHandler.handle(Priority.DEBUG, "Unexepected change type " + + message.getChangeType() + " for group \"" + key + "\""); + } + return stateChange; + } + + /** + * Check the message's file name to see if it needs to be removed from a + * pending delete list and see if it is time to delete the parent's + * directory. + * + * @param message + */ + private void checkGroupDelete(FileUpdatedMessage message) { + String filename = message.getFileName(); + String deleteKey = filename.substring(0, + filename.lastIndexOf(File.separator)); + List childList = groupDeleteMap.get(deleteKey); + if (childList != null) { + childList.remove(filename); + if (childList.size() == 0) { + LocalizationFile lFile = pathMgr.getLocalizationFile(userCtx, + deleteKey); + try { + lFile.delete(); + } catch (LocalizationOpFailedException e) { + statusHandler.handle(Priority.PROBLEM, + e.getLocalizedMessage(), e); + } + groupDeleteMap.remove(deleteKey); } } } @@ -1023,58 +1223,41 @@ public class PointsDataManager implements ILocalizationFileObserver, public void addPoint(final Point point) { Assert.isTrue(!point.isGroup()); - Job job = new Job("ADD POINT") { - @Override - public IStatus run(IProgressMonitor monitor) { - synchronized (groupUpdate) { - groupUpdate.set(true); - String name = point.getName(); - name = PointUtilities.trimAll(name); - Point foundPoint = getPoint(name); - if (foundPoint != null - && !foundPoint.getGroup().equals(point.getGroup())) { - ++cntPointsToUpdate; - doDeletePoint(foundPoint); - } - doAddPoint(point); - waitForUpdate(); - firePointChangeListeners(); - groupUpdate.set(false); - } - return Status.OK_STATUS; - } - }; - job.schedule(); + String key = getPointKey(point); + Point foundPoint = getPointsMap().get(key); + + PointRequest request = null; + + if (foundPoint == null) { + request = new PointRequest(RequestType.ADD, point); + childrenKeyMap.get(getParentKey(point)).add(key); + } else { + request = new PointRequest(RequestType.UPDATE, point); + } + queueRequest(request); + + put(key, point); + processRequests(); + } + + private void doAddPoint(Point point) { + PointRequest request = new PointRequest(RequestType.ADD, point); + queueRequest(request); } /** - * Try to add a new Point to the persistent store; the boolean flag just - * let's user know e.g. if Point was a duplicate. The server will return - * asynchronously via ILocalizationFileObserver::fileUpdated and a - * FileUpdatedMessage status of ADDED if file was successfully created. + * The server will return asynchronously via + * ILocalizationFileObserver::fileUpdated and a FileUpdatedMessage status of + * ADDED if file was successfully created. * * @param point * @return returns true if point was successfully added, false otherwise, * for example when a duplicate point name exists and forceOverwrite * was false */ - private boolean doAddPoint(Point point) { - boolean pointAdded; - String name = point.getName(); - name = PointUtilities.trimAll(name); - Point foundPoint = getPoint(name); - // already exists? - if (foundPoint != null) { - pointAdded = false; - } else { - pointAdded = true; - } + private void storePoint(Point point) { LocalizationFile dir = getGroupDir(point); - if (groupUpdate.get()) { - ++cntPointsToUpdate; - } storePoint(dir, point); - return pointAdded; } /** @@ -1088,110 +1271,56 @@ public class PointsDataManager implements ILocalizationFileObserver, * @return */ public void deletePoint(final Point point) { - if (!point.isGroup()) { - doDeletePoint(point); - return; - } - - Job job = new Job("DELETE_GROUP") { - - @Override - protected IStatus run(IProgressMonitor monitor) { - synchronized (groupUpdate) { - groupUpdate.set(true); - ++cntPointsToUpdate; - doDeletePoint(point); - waitForUpdate(); - firePointChangeListeners(); - groupUpdate.set(false); - } - return Status.OK_STATUS; - } - }; - job.schedule(); + doDeletePoint(point); + processRequests(); } private void doDeletePoint(Point point) { - String key = null; - if (point.isGroup()) { - key = point.getGroup(); - } else { - key = point.getName(); - } + String key = getPointKey(point); Point foundPoint = getPoint(key); - if (foundPoint != null) { - if (!foundPoint.isGroup()) { - removePoint(foundPoint); - } else { - // When removing a group node we need to delete the directory - // that represents the node. That can not be done until all - // entries in the directory are removed. This determines - // what we need to have deleted and adds the list to the - // pendingDeletes map so the fileUpdated() method can determine - // when it is safe to remove the directory.. - List deleteList = new ArrayList(); - String group = getPointDirName(foundPoint) + File.separator - + GROUP_INFO; - LocalizationFile gplf = pathMgr.getLocalizationFile(userCtx, - group); - if (gplf.exists()) { - ++cntPointsToUpdate; - deleteList.add(group); - } - List children = getChildren(foundPoint); - for (IPointNode child : children) { - Point childPoint = (Point) child; - ++cntPointsToUpdate; - if (child.isGroup()) { - deleteList.add(getPointDirName(childPoint)); - } else { - deleteList.add(getPointFilename(childPoint)); - } - } + PointRequest request = null; + String pointKey = getPointKey(foundPoint); + String parentKey = getParentKey(foundPoint); + String deleteKey = getPointDirName(foundPoint); - if (deleteList.size() > 0) { - // Delete children and wait for verification before - // deleting the directory. - pendingDeletes.put(key, deleteList); - for (IPointNode child : children) { - doDeletePoint((Point) child); - } + if (foundPoint.isGroup()) { + // When removing a group node we need to delete the directory + // that represents the node. That can not be done until all + // entries in the directory are removed. This determines + // what we need to have deleted and adds requests to the queue. + String groupInfo = deleteKey + File.separator + GROUP_INFO; + groupDeleteMap.put(deleteKey, new ArrayList()); + groupDeleteMap.get(deleteKey).add(groupInfo); - if (gplf.exists()) { - try { - gplf.delete(); - } catch (LocalizationOpFailedException e) { - statusHandler.handle(Priority.PROBLEM, - "unable to delete: " + group); - } - } - } else { - // Directory is empty and safe to delete. - String dirName = getPointDirName(foundPoint); - LocalizationFile lf = pathMgr.getLocalizationFile(userCtx, - dirName); - try { - lf.delete(); - } catch (LocalizationOpFailedException e) { - statusHandler.error("Unable to remove: " + group); - } - } + List children = getChildren(foundPoint, true); + for (IPointNode child : children) { + doDeletePoint((Point) child); + } + childrenKeyMap.remove(pointKey); + } else { + List childList = groupDeleteMap.get(deleteKey); + if (childList != null) { + childList.add(getPointFilename(foundPoint)); } } + request = new PointRequest(RequestType.DELETE, foundPoint); + queueRequest(request); + childrenKeyMap.get(parentKey).remove(pointKey); + remove(pointKey); } /*** * Try to remove a Point file from the persistent store; fires an * ILocalizationFileObserver event. * - * @param m - * @return + * @param point */ private void removePoint(Point point) { LocalizationFile lFile = null; if (point.isGroup()) { - lFile = getGroupDir(point); + String name = getPointDirName(point) + File.separator + GROUP_INFO; + lFile = pathMgr.getLocalizationFile(userCtx, name); } else { String name = getPointFilename(point); lFile = pathMgr.getLocalizationFile(userCtx, name); @@ -1207,75 +1336,65 @@ public class PointsDataManager implements ILocalizationFileObserver, } public void updatePoint(final Point oldPoint, final Point newPoint) { - Job job = new Job("POINT UPDATE") { + PointRequest request = null; - @Override - protected IStatus run(IProgressMonitor monitor) { - synchronized (groupUpdate) { - groupUpdate.set(true); - if (!oldPoint.getName().equals(newPoint.getName()) - || !oldPoint.getGroup().equals(newPoint.getGroup())) { - ++cntPointsToUpdate; - doDeletePoint(oldPoint); - } - doAddPoint(newPoint); - waitForUpdate(); - firePointChangeListeners(); - groupUpdate.set(false); - } - return Status.OK_STATUS; - } - - }; - job.schedule(); + if (!oldPoint.getName().equals(newPoint.getName()) + || !oldPoint.getGroup().equals(newPoint.getGroup())) { + // Points name or group changed need to remove old point and add + // new. + request = new PointRequest(RequestType.DELETE, oldPoint); + queueRequest(request); + String oldParentKey = getParentKey(oldPoint); + String oldKey = getPointKey(oldPoint); + childrenKeyMap.get(oldParentKey).remove(oldKey); + request = new PointRequest(RequestType.ADD, newPoint); + queueRequest(request); + String newParentKey = getParentKey(newPoint); + String newKey = getPointKey(newPoint); + childrenKeyMap.get(newParentKey).add(newKey); + remove(oldKey); + put(newKey, newPoint); + } else { + request = new PointRequest(RequestType.UPDATE, newPoint); + queueRequest(request); + put(getPointKey(newPoint), newPoint); + } + processRequests(); } public void updatePoint(Point point) throws PointNameChangeException { + Assert.isTrue(point != null && !point.isGroup()); Point oldPoint = getPoint(point.getName()); if (oldPoint == null) { throw new PointNameChangeException("Point does not exist"); } - LocalizationFile dir = getGroupDir(point); - storePoint(dir, point); + addPoint(point); } public void updateChildrenHidden(IPointNode node, boolean state) { if (!node.isGroup()) { return; } - - synchronized (groupUpdate) { - groupUpdate.set(true); - doChildrenHidden(node, state); - waitForUpdate(); - groupUpdate.set(false); - firePointChangeListeners(); - } + doChildrenHidden(node, state); + processRequests(); } private void doChildrenHidden(IPointNode node, boolean state) { - String path = getPointDirName((Point) node); - LocalizationFile[] files = pathMgr.listFiles(userCtx, path, - new String[] { POINT_FILENAME_EXT }, true, false); - Point point = null; - for (LocalizationFile lf : files) { - point = loadPoint(lf); - boolean oldState = point.isHidden(); + String key = getPointKey((Point) node); + Point point = points.get(key); + PointRequest request = null; + + if (!point.isGroup()) { + if (point.isHidden() != state) { + point.setHidden(state); + request = new PointRequest(RequestType.UPDATE, point); + queueRequest(request); + } + } else { point.setHidden(state); - if (state != oldState) { - if (lf.isDirectory()) { - put(getPointKey(lf), point); - } else { - try { - ++cntPointsToUpdate; - updatePoint(point); - } catch (PointNameChangeException e) { - statusHandler.handle( - Priority.PROBLEM, - "Unable up point's hidden state: " - + point.getName()); - } - } + List children = getChildren(point); + for (IPointNode child : children) { + doChildrenHidden(child, state); } } } @@ -1284,103 +1403,30 @@ public class PointsDataManager implements ILocalizationFileObserver, if (!node.isGroup()) { return; } - - synchronized (groupUpdate) { - groupUpdate.set(true); - doChildrenMovable(node, state); - waitForUpdate(); - groupUpdate.set(false); - firePointChangeListeners(); - } + doChildrenMovable(node, state); + processRequests(); } private void doChildrenMovable(IPointNode node, boolean state) { - String path = getPointDirName((Point) node); - LocalizationFile[] files = pathMgr.listFiles(userCtx, path, - new String[] { POINT_FILENAME_EXT }, true, false); - Point point = null; - for (LocalizationFile lf : files) { - point = loadPoint(lf); - boolean oldState = point.isMovable(); + String key = getPointKey((Point) node); + Point point = points.get(key); + PointRequest request = null; + + if (!point.isGroup()) { + if (point.isMovable() != state) { + point.setMovable(state); + request = new PointRequest(RequestType.UPDATE, point); + queueRequest(request); + } + } else { point.setMovable(state); - if (oldState != state) { - if (lf.isDirectory()) { - put(getPointKey(lf), point); - } else { - try { - ++cntPointsToUpdate; - updatePoint(point); - } catch (PointNameChangeException e) { - statusHandler.handle( - Priority.PROBLEM, - "Unable up point's movable state: " - + point.getName()); - } - } + List children = getChildren(point); + for (IPointNode child : children) { + doChildrenMovable(child, state); } } } - /* - * (non-Javadoc) - * - * @see - * org.eclipse.core.runtime.Preferences.IPropertyChangeListener#propertyChange - * (org.eclipse.core.runtime.Preferences.PropertyChangeEvent) - */ - @Override - public void propertyChange(PropertyChangeEvent event) { - } - - /** - * This method is used to catch a number of calls to fileUpdated without - * calling the firePointChangedListeners. This allows moving, updating, and - * deleting of several points all at once. - *

- * This method should only be called when in a synchronized block for - * groupUpdate and groupUpdate is set to true. It is assumed that - * cntPointsToUpdate is the number of times we need to wait for fileUpdated - * to be called. fileUpdated will increment cntPointsUpdated and perform a - * notify. This will return once the cntPointsUpdated equals - * cntPointsToUpdate. - *

- *

- * It is the responsibility of the calling method to perform a - * firePointChangeListeners to update displays. - *

- */ - private void waitForUpdate() { - if (cntPointsToUpdate == 0) { - // Nothing to wait for - cntPointsUpdated = 0; - return; - } - - // Since we cannot fully control what is happening with localized files - // and directories the cntDown allows up to break out of the loop if no - // update is received in 0.5 seconds. Otherwise this could freeze the - // display. - int cntDown = 5; - int oldUpdated = cntPointsUpdated; - while (cntPointsToUpdate != cntPointsUpdated && cntDown != 0) { - try { - groupUpdate.wait(100L); - if (oldUpdated == cntPointsUpdated) { - --cntDown; - } else { - oldUpdated = cntPointsUpdated; - cntDown = 5; - } - } catch (InterruptedException e) { - statusHandler.handle(Priority.PROBLEM, e.getLocalizedMessage(), - e); - } - } - - cntPointsToUpdate = 0; - cntPointsUpdated = 0; - } - /** * Use JAXB to convert a point to xml and save it in the localized file. * diff --git a/cave/com.raytheon.uf.viz.points/src/com/raytheon/uf/viz/points/data/Point.java b/cave/com.raytheon.uf.viz.points/src/com/raytheon/uf/viz/points/data/Point.java index b76760f0d8..859f767f9b 100644 --- a/cave/com.raytheon.uf.viz.points/src/com/raytheon/uf/viz/points/data/Point.java +++ b/cave/com.raytheon.uf.viz.points/src/com/raytheon/uf/viz/points/data/Point.java @@ -58,6 +58,10 @@ import com.vividsolutions.jts.geom.Coordinate; @XmlRootElement(name = "point") @DynamicSerialize public class Point implements IPointNode, Comparable { + /** + * This is used to compare the double values of latitude and longitude. + */ + private static final double DELTA = 0.000001; @XmlElement(name = "name") @DynamicSerializeElement @@ -105,7 +109,7 @@ public class Point implements IPointNode, Comparable { } /** - * Copy contructor. + * Copy constructor. * * @param point */ @@ -135,7 +139,7 @@ public class Point implements IPointNode, Comparable { */ public Point(String pointName, Coordinate p, boolean colorActive, RGB c, boolean hidden, boolean Movable, PointSize ms, String group) { - this.name = PointUtilities.trimAll(pointName); + setName(pointName); this.longitude = p.x; this.latitude = p.y; this.colorActive = colorActive; @@ -145,7 +149,7 @@ public class Point implements IPointNode, Comparable { this.hidden = hidden; this.movable = Movable; this.fontSize = ms; - this.group = group; + setGroup(group); } /** @@ -162,7 +166,7 @@ public class Point implements IPointNode, Comparable { */ public Point(String pointName, double lat, double lon, boolean hidden, boolean movable, boolean colorActive, RGB c, String group) { - this.name = PointUtilities.trimAll(pointName); + setName(pointName); this.fontSize = PointSize.DEFAULT; this.colorActive = colorActive; this.red = c.red; @@ -172,7 +176,7 @@ public class Point implements IPointNode, Comparable { this.hidden = hidden; this.longitude = lon; this.latitude = lat; - this.group = group.replace(' ', PointUtilities.DELIM_CHAR); + setGroup(group); } /** @@ -189,7 +193,7 @@ public class Point implements IPointNode, Comparable { */ public Point(String pointName, double lat, double lon, boolean movable, boolean colorActive, RGB c, PointSize size, String group) { - this.name = PointUtilities.trimAll(pointName); + setName(pointName); this.fontSize = size; this.colorActive = colorActive; this.red = c.red; @@ -199,7 +203,7 @@ public class Point implements IPointNode, Comparable { this.hidden = false; this.longitude = lon; this.latitude = lat; - this.group = group.replace(' ', PointUtilities.DELIM_CHAR); + setGroup(group); } /** @@ -259,7 +263,7 @@ public class Point implements IPointNode, Comparable { * @param pointName */ public void setName(String pointName) { - name = pointName; + name = PointUtilities.trimAll(pointName); } /** @@ -364,7 +368,8 @@ public class Point implements IPointNode, Comparable { * @param group */ public void setGroup(String group) { - this.group = group; + this.group = PointUtilities.trimAll(group).replace( + PointUtilities.DELIM_CHAR, ' '); } /* @@ -455,4 +460,38 @@ public class Point implements IPointNode, Comparable { } return getName().compareToIgnoreCase(o.getName()); } + + /** + * Determine if any of the contains of point is different. + * + * @param point + * @return state true when contains differ otherwise false + */ + public boolean differentContent(Point point) { + boolean state = false; + if (!name.equals(point.name)) { + state = true; + } else if (Math.abs(latitude - point.latitude) > DELTA) { + state = true; + } else if (Math.abs(longitude - point.longitude) > DELTA) { + state = true; + } else if (colorActive != point.colorActive) { + state = true; + } else if (red != point.red) { + state = true; + } else if (green != point.green) { + state = true; + } else if (blue != point.blue) { + state = true; + } else if (hidden != point.hidden) { + state = true; + } else if (movable != point.movable) { + state = true; + } else if (fontSize != point.fontSize) { + state = true; + } else if (!group.equals(point.group)) { + state = true; + } + return state; + } } diff --git a/cave/com.raytheon.uf.viz.points/src/com/raytheon/uf/viz/points/ui/dialog/PointTreeContentProvider.java b/cave/com.raytheon.uf.viz.points/src/com/raytheon/uf/viz/points/ui/dialog/PointTreeContentProvider.java index 1a03e52938..3ee71d6530 100644 --- a/cave/com.raytheon.uf.viz.points/src/com/raytheon/uf/viz/points/ui/dialog/PointTreeContentProvider.java +++ b/cave/com.raytheon.uf.viz.points/src/com/raytheon/uf/viz/points/ui/dialog/PointTreeContentProvider.java @@ -60,13 +60,13 @@ public class PointTreeContentProvider implements ITreeContentProvider { @Override public Object[] getElements(Object inputElement) { IPointNode node = (IPointNode) inputElement; - return manager.getChildren(node).toArray(new IPointNode[0]); + return manager.getChildren(node, true).toArray(new IPointNode[0]); } @Override public Object[] getChildren(Object parentElement) { IPointNode node = (IPointNode) parentElement; - List children = manager.getChildren(node); + List children = manager.getChildren(node, true); return children.toArray(new IPointNode[0]); } @@ -79,6 +79,6 @@ public class PointTreeContentProvider implements ITreeContentProvider { @Override public boolean hasChildren(Object element) { IPointNode node = (IPointNode) element; - return node.isGroup() && manager.getChildren(node).size() > 0; + return node.isGroup() && manager.getChildren(node, true).size() > 0; } } diff --git a/cave/com.raytheon.uf.viz.points/src/com/raytheon/uf/viz/points/ui/dialog/PointTreeDropListener.java b/cave/com.raytheon.uf.viz.points/src/com/raytheon/uf/viz/points/ui/dialog/PointTreeDropListener.java index 103c18a8c8..00eb9742a0 100644 --- a/cave/com.raytheon.uf.viz.points/src/com/raytheon/uf/viz/points/ui/dialog/PointTreeDropListener.java +++ b/cave/com.raytheon.uf.viz.points/src/com/raytheon/uf/viz/points/ui/dialog/PointTreeDropListener.java @@ -119,7 +119,7 @@ public class PointTreeDropListener extends ViewerDropAdapter { * @return true if child group node exists. */ private boolean childGroupExists(IPointNode parent, String name) { - for (IPointNode child : manager.getChildren(parent)) { + for (IPointNode child : manager.getChildren(parent, true)) { if (child.isGroup() && name.equals(child.getName())) { return true; } diff --git a/cave/com.raytheon.uf.viz.points/src/com/raytheon/uf/viz/points/ui/dialog/PointsMgrDialog.java b/cave/com.raytheon.uf.viz.points/src/com/raytheon/uf/viz/points/ui/dialog/PointsMgrDialog.java index e733f9614b..239e99d5bc 100644 --- a/cave/com.raytheon.uf.viz.points/src/com/raytheon/uf/viz/points/ui/dialog/PointsMgrDialog.java +++ b/cave/com.raytheon.uf.viz.points/src/com/raytheon/uf/viz/points/ui/dialog/PointsMgrDialog.java @@ -574,7 +574,7 @@ public class PointsMgrDialog extends CaveJFACEDialog implements } private boolean groupExists(IPointNode parent, String name) { - for (IPointNode child : dataManager.getChildren(parent)) { + for (IPointNode child : dataManager.getChildren(parent, true)) { if (child.isGroup() && name.equals(child.getName())) { return true; }