1 package tim.prune.function;
3 import java.util.Arrays;
5 import javax.swing.JOptionPane;
8 import tim.prune.I18nManager;
9 import tim.prune.data.Checker;
10 import tim.prune.data.DataPoint;
11 import tim.prune.data.Track;
12 import tim.prune.data.sort.SortMode;
13 import tim.prune.data.sort.WaypointComparer;
14 import tim.prune.undo.UndoRearrangeWaypoints;
17 * Class to provide the function for rearranging waypoints
19 public class RearrangeWaypointsFunction extends RearrangeFunction
24 * @param inApp app object
26 public RearrangeWaypointsFunction(App inApp)
31 /** Get the name key */
32 public String getNameKey() {
33 return "function.rearrangewaypoints";
36 /** Get whether sorting by time is allowed or not */
37 protected boolean isSortByTimeAllowed() {
38 return Checker.haveWaypointsGotTimestamps(_app.getTrackInfo().getTrack());
41 /** Get the description key */
42 public String getDescriptionKey() {
43 return "dialog.rearrangewaypoints.desc";
46 /** Sort by name key */
47 protected String getSortNameKey() {
52 * Perform the rearrange and sort according to the radio buttons
54 protected void finish()
56 Track track = _app.getTrackInfo().getTrack();
57 // Figure out what is required from the radio buttons
58 Rearrange rearrangeOption = getRearrangeOption();
59 SortMode sortOption = getSortMode();
61 UndoRearrangeWaypoints undo = new UndoRearrangeWaypoints(track);
62 boolean success = false;
63 if (rearrangeOption == Rearrange.TO_START || rearrangeOption == Rearrange.TO_END)
65 // Collect the waypoints to the start or end of the track
66 success = collectWaypoints(rearrangeOption, sortOption);
70 // Interleave the waypoints into track order
71 success = track.interleaveWaypoints();
75 _app.getTrackInfo().getSelection().clearAll(); // clear selected point and range
76 _app.completeFunction(undo, I18nManager.getText("confirm.rearrangewaypoints"));
80 JOptionPane.showMessageDialog(_parentFrame, I18nManager.getText("error.rearrange.noop"),
81 I18nManager.getText("error.function.noop.title"), JOptionPane.WARNING_MESSAGE);
87 * Do the collection and sorting of the waypoints
88 * @param inRearrangeOption beginning or end
89 * @param inSortOption optional sort criterion
90 * @return true on success
92 private boolean collectWaypoints(Rearrange inRearrangeOption, SortMode inSortOption)
94 // Check for mixed data, numbers of waypoints & nons
95 int numWaypoints = 0, numNonWaypoints = 0;
96 boolean wayAfterNon = false, nonAfterWay = false;
97 Track track = _app.getTrackInfo().getTrack();
98 final int numPoints = track.getNumPoints();
99 DataPoint[] waypoints = new DataPoint[numPoints];
100 DataPoint[] nonWaypoints = new DataPoint[numPoints];
101 DataPoint point = null;
102 for (int i=0; i<numPoints; i++)
104 point = track.getPoint(i);
105 if (point.isWaypoint())
107 waypoints[numWaypoints] = point;
109 wayAfterNon |= (numNonWaypoints > 0);
113 nonWaypoints[numNonWaypoints] = point;
115 nonAfterWay |= (numWaypoints > 0);
119 // Exit if the data is already in the specified order
120 final boolean wpsToStart = (inRearrangeOption == Rearrange.TO_START);
121 final boolean doSort = (inSortOption != SortMode.DONT_SORT);
122 if (numWaypoints == 0
123 || (wpsToStart && !wayAfterNon && nonAfterWay && !doSort)
124 || (!wpsToStart && wayAfterNon && !nonAfterWay && !doSort)
125 || inRearrangeOption == Rearrange.TO_NEAREST)
129 // Note: it could still be that the rearrange and sort has no effect, but we don't know yet
130 // Make a copy of the waypoints array first so we can compare it with after the sort
131 DataPoint[] origWaypoints = new DataPoint[numPoints];
132 System.arraycopy(waypoints, 0, origWaypoints, 0, numPoints);
134 if (doSort && numWaypoints > 1)
136 // Sort the waypoints array
137 WaypointComparer comparer = new WaypointComparer(inSortOption);
138 Arrays.sort(waypoints, comparer);
139 final boolean sortDidNothing = areArraysSame(origWaypoints, waypoints);
140 if (sortDidNothing && (numNonWaypoints == 0
141 || (wpsToStart && !wayAfterNon && nonAfterWay)
142 || (!wpsToStart && wayAfterNon && !nonAfterWay)))
148 // Copy the arrays into an array in the specified order
149 DataPoint[] neworder = new DataPoint[numPoints];
152 System.arraycopy(waypoints, 0, neworder, 0, numWaypoints);
153 System.arraycopy(nonWaypoints, 0, neworder, numWaypoints, numNonWaypoints);
157 System.arraycopy(nonWaypoints, 0, neworder, 0, numNonWaypoints);
158 System.arraycopy(waypoints, 0, neworder, numNonWaypoints, numWaypoints);
160 // Give track the new point order
161 return track.replaceContents(neworder);
165 * Compare two arrays of DataPoints and see if they're identical or not
166 * @param inOriginal original array of points
167 * @param inSorted array of points after sorting
168 * @return true if the two arrays have the same points in the same order
170 private static boolean areArraysSame(DataPoint[] inOriginal, DataPoint[] inSorted)
172 if (inOriginal == null && inSorted == null) return true; // both null
173 if (inOriginal == null || inSorted == null) return false; // only one of them null
174 if (inOriginal.length != inSorted.length) return false;
175 // Loop over all points
176 for (int i=0; i<inOriginal.length; i++)
178 DataPoint origPoint = inOriginal[i];
179 DataPoint sortedPoint = inSorted[i];
180 if ((origPoint != null || sortedPoint != null)
181 && (origPoint != sortedPoint))
183 return false; // points different
186 // Must be all the same