]> gitweb.fperrin.net Git - GpsPrune.git/blob - src/tim/prune/function/RearrangeWaypointsFunction.java
17e937027c2d021593979e7c54fefcdf4851f940
[GpsPrune.git] / src / tim / prune / function / RearrangeWaypointsFunction.java
1 package tim.prune.function;
2
3 import java.util.Arrays;
4
5 import javax.swing.JOptionPane;
6
7 import tim.prune.App;
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;
15
16 /**
17  * Class to provide the function for rearranging waypoints
18  */
19 public class RearrangeWaypointsFunction extends RearrangeFunction
20 {
21
22         /**
23          * Constructor
24          * @param inApp app object
25          */
26         public RearrangeWaypointsFunction(App inApp)
27         {
28                 super(inApp, true);
29         }
30
31         /** Get the name key */
32         public String getNameKey() {
33                 return "function.rearrangewaypoints";
34         }
35
36         /** Get whether sorting by time is allowed or not */
37         protected boolean isSortByTimeAllowed() {
38                 return Checker.haveWaypointsGotTimestamps(_app.getTrackInfo().getTrack());
39         }
40
41         /** Get the description key */
42         public String getDescriptionKey() {
43                 return "dialog.rearrangewaypoints.desc";
44         }
45
46         /** Sort by name key */
47         protected String getSortNameKey() {
48                 return "sortbyname";
49         }
50
51         /**
52          * Perform the rearrange and sort according to the radio buttons
53          */
54         protected void finish()
55         {
56                 Track track = _app.getTrackInfo().getTrack();
57                 // Figure out what is required from the radio buttons
58                 Rearrange rearrangeOption = getRearrangeOption();
59                 SortMode sortOption = getSortMode();
60
61                 UndoRearrangeWaypoints undo = new UndoRearrangeWaypoints(track);
62                 boolean success = false;
63                 if (rearrangeOption == Rearrange.TO_START || rearrangeOption == Rearrange.TO_END)
64                 {
65                         // Collect the waypoints to the start or end of the track
66                         success = collectWaypoints(rearrangeOption, sortOption);
67                 }
68                 else
69                 {
70                         // Interleave the waypoints into track order
71                         success = track.interleaveWaypoints();
72                 }
73                 if (success)
74                 {
75                         _app.getTrackInfo().getSelection().clearAll(); // clear selected point and range
76                         _app.completeFunction(undo, I18nManager.getText("confirm.rearrangewaypoints"));
77                 }
78                 else
79                 {
80                         JOptionPane.showMessageDialog(_parentFrame, I18nManager.getText("error.rearrange.noop"),
81                                 I18nManager.getText("error.function.noop.title"), JOptionPane.WARNING_MESSAGE);
82                 }
83         }
84
85
86         /**
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
91          */
92         private boolean collectWaypoints(Rearrange inRearrangeOption, SortMode inSortOption)
93         {
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++)
103                 {
104                         point = track.getPoint(i);
105                         if (point.isWaypoint())
106                         {
107                                 waypoints[numWaypoints] = point;
108                                 numWaypoints++;
109                                 wayAfterNon |= (numNonWaypoints > 0);
110                         }
111                         else
112                         {
113                                 nonWaypoints[numNonWaypoints] = point;
114                                 numNonWaypoints++;
115                                 nonAfterWay |= (numWaypoints > 0);
116                         }
117                 }
118
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 || numNonWaypoints == 0
123                         || (wpsToStart && !wayAfterNon && nonAfterWay && !doSort)
124                         || (!wpsToStart && wayAfterNon && !nonAfterWay && !doSort)
125                         || inRearrangeOption == Rearrange.TO_NEAREST)
126                 {
127                         return false;
128                 }
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);
133
134                 if (doSort && numWaypoints > 1)
135                 {
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)))
143                         {
144                                 return false;
145                         }
146                 }
147
148                 // Copy the arrays into an array in the specified order
149                 DataPoint[] neworder = new DataPoint[numPoints];
150                 if (wpsToStart)
151                 {
152                         System.arraycopy(waypoints, 0, neworder, 0, numWaypoints);
153                         System.arraycopy(nonWaypoints, 0, neworder, numWaypoints, numNonWaypoints);
154                 }
155                 else
156                 {
157                         System.arraycopy(nonWaypoints, 0, neworder, 0, numNonWaypoints);
158                         System.arraycopy(waypoints, 0, neworder, numNonWaypoints, numWaypoints);
159                 }
160                 // Give track the new point order
161                 return track.replaceContents(neworder);
162         }
163
164         /**
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
169          */
170         private static boolean areArraysSame(DataPoint[] inOriginal, DataPoint[] inSorted)
171         {
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++)
177                 {
178                         DataPoint origPoint = inOriginal[i];
179                         DataPoint sortedPoint = inSorted[i];
180                         if ((origPoint != null || sortedPoint != null)
181                                 && (origPoint != sortedPoint))
182                         {
183                                 return false; // points different
184                         }
185                 }
186                 // Must be all the same
187                 return true;
188         }
189 }