package tim.prune.function; import java.util.Arrays; import javax.swing.JOptionPane; import tim.prune.App; import tim.prune.I18nManager; import tim.prune.data.Checker; import tim.prune.data.DataPoint; import tim.prune.data.Track; import tim.prune.data.sort.SortMode; import tim.prune.data.sort.WaypointComparer; import tim.prune.undo.UndoRearrangeWaypoints; /** * Class to provide the function for rearranging waypoints */ public class RearrangeWaypointsFunction extends RearrangeFunction { /** * Constructor * @param inApp app object */ public RearrangeWaypointsFunction(App inApp) { super(inApp, true); } /** Get the name key */ public String getNameKey() { return "function.rearrangewaypoints"; } /** Get whether sorting by time is allowed or not */ protected boolean isSortByTimeAllowed() { return Checker.haveWaypointsGotTimestamps(_app.getTrackInfo().getTrack()); } /** Get the description key */ public String getDescriptionKey() { return "dialog.rearrangewaypoints.desc"; } /** Sort by name key */ protected String getSortNameKey() { return "sortbyname"; } /** * Perform the rearrange and sort according to the radio buttons */ protected void finish() { Track track = _app.getTrackInfo().getTrack(); // Figure out what is required from the radio buttons Rearrange rearrangeOption = getRearrangeOption(); SortMode sortOption = getSortMode(); UndoRearrangeWaypoints undo = new UndoRearrangeWaypoints(track); boolean success = false; if (rearrangeOption == Rearrange.TO_START || rearrangeOption == Rearrange.TO_END) { // Collect the waypoints to the start or end of the track success = collectWaypoints(rearrangeOption, sortOption); } else { // Interleave the waypoints into track order success = track.interleaveWaypoints(); } if (success) { _app.getTrackInfo().getSelection().clearAll(); // clear selected point and range _app.completeFunction(undo, I18nManager.getText("confirm.rearrangewaypoints")); } else { JOptionPane.showMessageDialog(_parentFrame, I18nManager.getText("error.rearrange.noop"), I18nManager.getText("error.function.noop.title"), JOptionPane.WARNING_MESSAGE); } } /** * Do the collection and sorting of the waypoints * @param inRearrangeOption beginning or end * @param inSortOption optional sort criterion * @return true on success */ private boolean collectWaypoints(Rearrange inRearrangeOption, SortMode inSortOption) { // Check for mixed data, numbers of waypoints & nons int numWaypoints = 0, numNonWaypoints = 0; boolean wayAfterNon = false, nonAfterWay = false; Track track = _app.getTrackInfo().getTrack(); final int numPoints = track.getNumPoints(); DataPoint[] waypoints = new DataPoint[numPoints]; DataPoint[] nonWaypoints = new DataPoint[numPoints]; DataPoint point = null; for (int i=0; i 0); } else { nonWaypoints[numNonWaypoints] = point; numNonWaypoints++; nonAfterWay |= (numWaypoints > 0); } } // Exit if the data is already in the specified order final boolean wpsToStart = (inRearrangeOption == Rearrange.TO_START); final boolean doSort = (inSortOption != SortMode.DONT_SORT); if (numWaypoints == 0 || (wpsToStart && !wayAfterNon && nonAfterWay && !doSort) || (!wpsToStart && wayAfterNon && !nonAfterWay && !doSort) || inRearrangeOption == Rearrange.TO_NEAREST) { return false; } // Note: it could still be that the rearrange and sort has no effect, but we don't know yet // Make a copy of the waypoints array first so we can compare it with after the sort DataPoint[] origWaypoints = new DataPoint[numPoints]; System.arraycopy(waypoints, 0, origWaypoints, 0, numPoints); if (doSort && numWaypoints > 1) { // Sort the waypoints array WaypointComparer comparer = new WaypointComparer(inSortOption); Arrays.sort(waypoints, comparer); final boolean sortDidNothing = areArraysSame(origWaypoints, waypoints); if (sortDidNothing && (numNonWaypoints == 0 || (wpsToStart && !wayAfterNon && nonAfterWay) || (!wpsToStart && wayAfterNon && !nonAfterWay))) { return false; } } // Copy the arrays into an array in the specified order DataPoint[] neworder = new DataPoint[numPoints]; if (wpsToStart) { System.arraycopy(waypoints, 0, neworder, 0, numWaypoints); System.arraycopy(nonWaypoints, 0, neworder, numWaypoints, numNonWaypoints); } else { System.arraycopy(nonWaypoints, 0, neworder, 0, numNonWaypoints); System.arraycopy(waypoints, 0, neworder, numNonWaypoints, numWaypoints); } // Give track the new point order return track.replaceContents(neworder); } /** * Compare two arrays of DataPoints and see if they're identical or not * @param inOriginal original array of points * @param inSorted array of points after sorting * @return true if the two arrays have the same points in the same order */ private static boolean areArraysSame(DataPoint[] inOriginal, DataPoint[] inSorted) { if (inOriginal == null && inSorted == null) return true; // both null if (inOriginal == null || inSorted == null) return false; // only one of them null if (inOriginal.length != inSorted.length) return false; // Loop over all points for (int i=0; i